實質解決方法(精華帖)Comparison method violates its general contract!

源碼

listRs = list.stream().sorted((n1, n2) -> {
                    BigDecimal value1 = n1.getValue1();
                    BigDecimal value2 = n2.getValue1();
                    if (value1.subtract(value2).intValue() > 0) {
                        return -1;
                    }
                    if (value1.subtract(value2).intValue() < 0) {
                        return 1;
                    }
                    return 0;
        }).collect(Collectors.toList());

異常

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中的Collections.Sort方法實現中,如果兩個值是相等的,那麼compare方法需要返回0,否則 可能 會在排序時拋錯,而JDK6是沒有這個限制的。

這裏網上現有的解決方案有:
3. 解決方法
解決該問題至少有3種方法。

(1)使用JDK1.6版本運行

(2)修改The ONE源碼,使其滿足傳遞性

只需要更改Router的比較器Comparator就可以了,比如MaxProp的MaxPropComparator:

private class MaxPropComparator implements Comparator {

}
(3)重新編譯源碼

加上一些選項,重新編譯The ONE源碼,使其能在JDK1.6+能正常運行[1]。

方法一:在main函數第一行加入如下代碼:

System.setProperty(“java.util.Arrays.useLegacyMergeSort”, “true”);
方法2:編譯時,加上選項-Djava.util.Arrays.useLegacyMergeSort=true,完整Java編譯如下:

java -Djava.util.Arrays.useLegacyMergeSort=true -d64 -Xms512m -Xmx4g -cp .:lib/ECLA.jar:lib/DTNConsoleConnection.jar core.DTNSim $*

我的解決辦法:
1、網上也有提到,如果重寫了compare方法,需要判斷大於,小於,等於


2、用java的compareTo()方法,讓jdk去處理;


修改後

listRs = list.stream().sorted((n1, n2) -> {
                    BigDecimal value1 = n1.getValue1();
                    BigDecimal value2 = n2.getValue1();
                    //倒序,所以乘 -1
                    return -1 * value1.compareTo(value2);
        }).collect(Collectors.toList());
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章