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:410)
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)
我正在根据以下比较器对集合进行排序。
public static Comparator<MyClass> CMP_TIME_DESC = new Comparator<MyClass>() {
@Override
public int compare(MyClass o1, MyClass o2) {
return o2.getOrderSendTime().compareTo(o1.getOrderSendTime());
}
};
值始终为非null。 getOrderSendTime()对象属于java.util.Date类。
我知道这是一个传递性不一致的地方,我认为像这样的课程不会有这样的问题。我搜索了未解决的问题,但没有找到关于该主题的任何内容。
有什么想法吗?
答案 0 :(得分:3)
您的问题与此问题有关:Sort algorithm changes in Java 7
这是因为默认排序算法有changed from MergeSort to TimSort。
一种解决方法是将-Djava.util.Arrays.useLegacyMergeSort=true
添加到JVM环境中。
最好的选择是遵守比较一般合同,但我认为您没有在此问题中提供足够的信息。
答案 1 :(得分:3)
我有同样的异常,当我在Java8上运行排序时,我在同一列表/数组中有java.util.Date
和java.sql.Timestamp
个对象时发生了这种情况。 (这种混合是由于某些对象是从具有Timestamp
数据类型的数据库记录加载的,而其他对象是手动创建的,而对象中只有Date
个对象。)
每次对同一数据集进行排序时也不会发生异常,并且似乎阵列中至少还有32个这样的混合对象才会发生。
如果我使用传统排序算法,这也不会发生(请参阅Ortomala Lokni的回答)。
如果您只使用数组中的java.util.Date
个对象或java.sql.Timestamp
个对象,也不会发生这种情况。
因此,问题似乎是TimSort
与java.util.Date
和java.sql.Timestamp
中的compareTo方法相结合。
然而,由于它已在Java 9中得到修复,因此我无法研究为什么会发生这种情况!
作为一种解决方法,直到Java9发布并且我们可以更新系统,我们已手动实施仅使用Comparator
的{{1}}。这似乎工作正常。
以下是可用于重现问题的代码:
getTime()
修改:我已删除异常预期,因此您可以在运行时看到它抛出。
答案 2 :(得分:0)
添加&#34; -Djava.util.Arrays.useLegacyMergeSort = true&#34;到VM参数。
答案 3 :(得分:0)
在花了几个小时之后,今天面对了这个问题,意识到我正在比较Longs。相反,您需要比较Long.longValue()。
MyData.utcTime()返回Long。所以代替:
public static Comparator<MyData> sortByUtcPublishedDesc = new Comparator<MyData>() {
@Override
public int compare(MyData n1, MyData n2) {
if ( n2.utcTime() < n1.utcTime() )
return -1;
if ( n2.utcTime() == n1.utcTime() )
return 0;
// if (n2.utcTime() > n1.utcTime())
return 1;
}
};
我用以下方法解决问题。
public static Comparator<MyData> sortByUtcPublishedDesc = new Comparator<MyData>() {
@Override
public int compare(MyData n1, MyData n2) {
if ( n2.utcTime().longValue() < n1.utcTime().longValue() )
return -1;
if ( n2.utcTime().longValue() == n1.utcTime().longValue() )
return 0;
// if (n2.utcTime() > n1.utcTime())
return 1;
}
};