-Djava.util.Arrays.useLegacyMergeSort=true 兼容排序問題

java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:868)
at java.util.TimSort.mergeAt(TimSort.java:485)
at java.util.TimSort.mergeCollapse(TimSort.java:408)
at java.util.TimSort.sort(TimSort.java:214)
at java.util.TimSort.sort(TimSort.java:173)
at java.util.Arrays.sort(Arrays.java:659)
at java.util.Collections.sort(Collections.java:217)

在 JDK7 版本以上,Comparator 要滿足自反性,傳遞性,對稱性,不然 Arrays.sort,

Collections.sort 會報 IllegalArgumentException 異常。

說明:

1) 自反性:x,y 的比較結果和 y,x 的比較結果相反。

2) 傳遞性:x>y,y>z,則 x>z。

3) 對稱性:x=y,則 x,z 比較結果和 y,z 比較結果相同。

重現

package com.sparrow.jdk.collections;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * -Djava.util.Arrays.useLegacyMergeSort=true
 */
public class DictionaryTest {
    public static void main(String[] args) {
        //exception
        int[] array = new int[]{1, 2, 3, 2, 2, 3, 2, 3, 2, 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};

        array = new int[]{2, 3, 2, 2, 3, 2, 3, 2, 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};

        List<DictionaryEntry> list = new ArrayList<>();
        Set<DictionaryEntry> set = new TreeSet<>();
        for (int i = 0; i < array.length; i++) {
            DictionaryEntry entry = new DictionaryEntry();
            entry.setItemId(i);
            entry.setScore(new BigDecimal(array[i]));
            list.add(entry);
            set.add(entry);
        }
        long current = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            //System.out.println(set.size());
            Collections.sort(list);
            //System.out.println(list.size());
        }
        System.out.println(System.currentTimeMillis() - current);
    }

    public static class DictionaryEntry implements Comparable<DictionaryEntry> {
        public DictionaryEntry() {
        }

        private Integer itemId;
        private BigDecimal score;

        public BigDecimal getScore() {
            return score;
        }

        public void setScore(BigDecimal score) {
            if (score != null) {
                this.score = score.setScale(5, RoundingMode.HALF_UP);
            } else {
                this.score = new BigDecimal(0);
            }
        }

        public Integer getItemId() {
            return itemId;
        }

        public void setItemId(Integer itemId) {
            this.itemId = itemId;
        }

        @Override
        public int compareTo(DictionaryEntry o) {
            //tree set o.score.compareTo(this.score)==0時去重
            //手動設置非0時,throw new IllegalArgumentException("Comparison method violates its general contract!");
            //-Djava.util.Arrays.useLegacyMergeSort=true 解決兼容
            return o.score.compareTo(this.score) == 0 ? -1 : o.score.compareTo(this.score);
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章