比较方法违反了其总合同! Java7 Comparator

时间:2015-08-13 09:02:52

标签: java comparator

java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.TimSort.mergeLo(TimSort.java:747)
    at java.util.TimSort.mergeAt(TimSort.java:483)
    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)

有人可以解释为什么我的比较器有时会抛出上述异常。

注意:myObject中的id字段是long类型。

Collections.sort(objectList, new Comparator<MyObject>() {

    @Override
    public int compare(final myObject myobject1, final MyObject myObject2) {

        return (int)(myObject1.getId() - myObject2.getId());

    }
});

解决方案:

基于@amit的答案

return (int)(Long.compare(myObject1.getId(), myObject2.getId());

2 个答案:

答案 0 :(得分:4)

如果ID的绝对值为相对较高的整数,则可能会遇到整数溢出,这会导致echo "# some change" >> Gemfile && git commit -m 'some change' Gemfile 为负数。这显然是错误的,并打破了比较国的合同。

使用Integer.compare()(或类似Long.compare()Double.compare() ...)而不是减去数字以避免它。

修改

具体来说,这里的问题仍然是整数溢出,当它输出一个long值时,其32个LSb在[{1}}到VERY_HIGH_INT - VERY_LOW_INT范围内[2 ^ 31,2 ^ 32],这会导致它错误的否定。 Demo in ideone

解决方案是一样的。使用long

答案 1 :(得分:0)

Java 7 已将MergeSort方法中的默认排序算法从TimSort更改为java.util.Arrays.sort

java.util.Arrays.sort和(indirectlyjava.util.Collections.sort使用的排序算法已被替换。如果新排序实现检测到违反Comparable合同的Comparable,则可能会抛出IllegalArgumentException

为了向后兼容并从Java版本6恢复行为,请添加新的系统属性 - java.util.Arrays.useLegacyMergeSort

有关详细信息,请参阅以下链接 -

http://www.oracle.com/technetwork/java/javase/compatibility-417013.html#source