比较方法违反了它的总契约! Java7 比较器

Comparison method violates its general contract! Java7 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());

如果ID是绝对值较高的整数,可能会遇到整数溢出,导致VERY_HIGH_INT - VERY_LOW_INT为负数。这显然是错误的,并且破坏了比较器的契约。

使用 Integer.compare() (or similarly Long.compare(), Double.compare()...) 而不是减去数字来避免它。


编辑:

特别是这里,问题仍然是整数溢出,当它的 32 LSbs 在 [2^31,2^32) 从 longint 的范围内转换 long 值时,这导致它被错误地否定。 Demo in ideone.

解决方法是一样的。使用 Long.compare()

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

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

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

详情请参考以下link -

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