比较方法违反了它的总契约! 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) 从 long
到 int
的范围内转换 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
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) 从 long
到 int
的范围内转换 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