【问题标题】:Comparison method violates its general contract! Java7 Comparator比较法违反其总约! Java7 比较器
【发布时间】:2015-08-13 09:02:51
【问题描述】:
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());

【问题讨论】:

  • myObject 应该有一个大写的 M - Java 代码约定不是可选的,类总是以大写字母开头。
  • @LionC 道歉,这是一个错字。这不是造成问题的原因。
  • @Eran 不,集合中不可能有空值
  • @LionC 代码约定始终是可选的;只是不建议偏离这样的惯例。

标签: java comparator


【解决方案1】:

如果 ID 是绝对值相对较高的整数,您可能会遇到整数溢出,这将导致 VERY_HIGH_INT - VERY_LOW_INT 为负数。这显然是错误的,并且违反了比较器的合同。

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


编辑:

特别是这里,问题仍然是整数溢出,当它的 32 个 LSbs 在从longint 的范围 [2^31,2^32) 的长值时,这会导致它错误地为负. Demo in ideone.

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

【讨论】:

  • 只要只使用正整数 ID,这应该不是问题。如果你需要更多的 id,我会考虑使用无符号比较,这样 id 0 总是第一个。
  • id基于System.currentTimeMillis()
  • @user5222688 见编辑。问题还是整数溢出。
  • @kajacx 当您将 long 转换为 int 时,这仍然是一个问题。见编辑。
  • @amit 你是正确的。谢谢。
【解决方案2】:

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

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

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

详情请参考以下链接 -

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

【讨论】:

  • 虽然内容丰富,但并不能回答问题。 OP 熟悉合约,并不真正关心涉及哪种排序算法。他关心为什么他的比较器中的合同被破坏,而这并没有回答它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多