java.lang.IllegalArgumentException: 比较方法违反了它的一般契约! java.util.Date
java.lang.IllegalArgumentException: Comparison method violates its general contract! java.util.Date
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());
}
};
值总是非空的。
而 getOrderSendTime() 对象属于 java.util.Date class.
我知道这是传递性不一致,我认为像这样的 class 不会有这样的问题。我搜索了未解决的问题,但没有找到任何关于该主题的内容。
有什么想法吗?
您的问题与此相关:Sort algorithm changes in Java 7
这是因为默认排序算法有 changed from MergeSort to TimSort。
一种解决方法是将 -Djava.util.Arrays.useLegacyMergeSort=true
添加到 JVM 环境。
最好的选择是符合比较总合同,但我认为您在问题中没有为此提供足够的信息。
我有同样的异常,它发生在我在排序时在同一个 list/array 中有 java.util.Date
和 java.sql.Timestamp
对象,运行ning 在 Java8。 (这种混合是由于一些对象是从具有 Timestamp
数据类型的数据库记录加载的,而其他对象是手动创建的,并且对象中只有一个 Date
对象。)
每次对同一个数据集进行排序时也不会发生异常,并且似乎数组中也必须至少有 32 个这样的混合对象才会发生。
如果我使用传统的排序算法,也不会发生这种情况(请参阅 Ortomala Lokni 的回答)。
如果您仅使用 java.util.Date
个对象或仅使用数组中的 java.sql.Timestamp
个对象,这也不会发生。
因此,问题似乎是 TimSort
与 java.util.Date
和 java.sql.Timestamp
中的 compareTo 方法相结合。
但是,我没有花钱研究为什么会发生这种情况,因为它已在 Java 9!
中修复
作为 Java9 发布之前的解决方法,我们可以更新系统,我们手动实施了仅使用 getTime()
的 Comparator
。这似乎工作正常。
这是可用于重现问题的代码:
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.junit.Test;
public class TimSortDateAndTimestampTest {
// the same test data with all Dates, all Timestamps, all Strings or all Longs does NOT fail.
// only fails with mixed Timestamp and Date objects
@Test
public void testSortWithTimestampsAndDatesFails() throws Exception {
List<Date> dates = new ArrayList<>();
dates.add(new Timestamp(1498621254602L));
dates.add(new Timestamp(1498621254603L));
dates.add(new Timestamp(1498621254603L));
dates.add(new Timestamp(1498621254604L));
dates.add(new Timestamp(1498621254604L));
dates.add(new Timestamp(1498621254605L));
dates.add(new Timestamp(1498621254605L));
dates.add(new Timestamp(1498621254605L));
dates.add(new Timestamp(1498621254605L));
dates.add(new Timestamp(1498621254606L));
dates.add(new Timestamp(1498621254607L));
dates.add(new Date(1498621254605L));
dates.add(new Timestamp(1498621254607L));
dates.add(new Timestamp(1498621254609L));
dates.add(new Date(1498621254603L));
dates.add(new Date(1498621254604L));
dates.add(new Date(1498621254605L));
dates.add(new Date(1498621254605L));
dates.add(new Date(1498621254607L));
dates.add(new Timestamp(1498621254607L));
dates.add(new Date(1498621254608L));
dates.add(new Timestamp(1498621254608L));
dates.add(new Date(1498621254611L));
dates.add(new Timestamp(1498621254612L));
dates.add(new Timestamp(1498621254613L));
dates.add(new Date(1498621254607L));
dates.add(new Timestamp(1498621254607L));
dates.add(new Timestamp(1498621254608L));
dates.add(new Timestamp(1498621254609L));
dates.add(new Timestamp(1498621254611L));
dates.add(new Date(1498621254603L));
dates.add(new Date(1498621254606L));
for (int i = 0; i < 200; i++) {
Collections.shuffle(dates);
Collections.sort(dates);
}
}
}
编辑: 我已经删除了异常预期,所以你可以看到它在 运行.
时抛出
将“-Djava.util.Arrays.useLegacyMergeSort=true”添加到 VM 参数。
今天遇到这个问题,花了几个小时后,意识到我在比较多头。相反,您需要比较 Long.longValue().
MyData.utcTime() returns 长。所以代替:
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;
}
};
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());
}
};
值总是非空的。 而 getOrderSendTime() 对象属于 java.util.Date class.
我知道这是传递性不一致,我认为像这样的 class 不会有这样的问题。我搜索了未解决的问题,但没有找到任何关于该主题的内容。
有什么想法吗?
您的问题与此相关:Sort algorithm changes in Java 7
这是因为默认排序算法有 changed from MergeSort to TimSort。
一种解决方法是将 -Djava.util.Arrays.useLegacyMergeSort=true
添加到 JVM 环境。
最好的选择是符合比较总合同,但我认为您在问题中没有为此提供足够的信息。
我有同样的异常,它发生在我在排序时在同一个 list/array 中有 java.util.Date
和 java.sql.Timestamp
对象,运行ning 在 Java8。 (这种混合是由于一些对象是从具有 Timestamp
数据类型的数据库记录加载的,而其他对象是手动创建的,并且对象中只有一个 Date
对象。)
每次对同一个数据集进行排序时也不会发生异常,并且似乎数组中也必须至少有 32 个这样的混合对象才会发生。
如果我使用传统的排序算法,也不会发生这种情况(请参阅 Ortomala Lokni 的回答)。
如果您仅使用 java.util.Date
个对象或仅使用数组中的 java.sql.Timestamp
个对象,这也不会发生。
因此,问题似乎是 TimSort
与 java.util.Date
和 java.sql.Timestamp
中的 compareTo 方法相结合。
但是,我没有花钱研究为什么会发生这种情况,因为它已在 Java 9!
中修复作为 Java9 发布之前的解决方法,我们可以更新系统,我们手动实施了仅使用 getTime()
的 Comparator
。这似乎工作正常。
这是可用于重现问题的代码:
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.junit.Test;
public class TimSortDateAndTimestampTest {
// the same test data with all Dates, all Timestamps, all Strings or all Longs does NOT fail.
// only fails with mixed Timestamp and Date objects
@Test
public void testSortWithTimestampsAndDatesFails() throws Exception {
List<Date> dates = new ArrayList<>();
dates.add(new Timestamp(1498621254602L));
dates.add(new Timestamp(1498621254603L));
dates.add(new Timestamp(1498621254603L));
dates.add(new Timestamp(1498621254604L));
dates.add(new Timestamp(1498621254604L));
dates.add(new Timestamp(1498621254605L));
dates.add(new Timestamp(1498621254605L));
dates.add(new Timestamp(1498621254605L));
dates.add(new Timestamp(1498621254605L));
dates.add(new Timestamp(1498621254606L));
dates.add(new Timestamp(1498621254607L));
dates.add(new Date(1498621254605L));
dates.add(new Timestamp(1498621254607L));
dates.add(new Timestamp(1498621254609L));
dates.add(new Date(1498621254603L));
dates.add(new Date(1498621254604L));
dates.add(new Date(1498621254605L));
dates.add(new Date(1498621254605L));
dates.add(new Date(1498621254607L));
dates.add(new Timestamp(1498621254607L));
dates.add(new Date(1498621254608L));
dates.add(new Timestamp(1498621254608L));
dates.add(new Date(1498621254611L));
dates.add(new Timestamp(1498621254612L));
dates.add(new Timestamp(1498621254613L));
dates.add(new Date(1498621254607L));
dates.add(new Timestamp(1498621254607L));
dates.add(new Timestamp(1498621254608L));
dates.add(new Timestamp(1498621254609L));
dates.add(new Timestamp(1498621254611L));
dates.add(new Date(1498621254603L));
dates.add(new Date(1498621254606L));
for (int i = 0; i < 200; i++) {
Collections.shuffle(dates);
Collections.sort(dates);
}
}
}
编辑: 我已经删除了异常预期,所以你可以看到它在 运行.
时抛出将“-Djava.util.Arrays.useLegacyMergeSort=true”添加到 VM 参数。
今天遇到这个问题,花了几个小时后,意识到我在比较多头。相反,您需要比较 Long.longValue().
MyData.utcTime() returns 长。所以代替:
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;
}
};