简体   繁体   English

java.lang.IllegalArgumentException:比较方法违反了它的一般约定! 日期

[英]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)

I am sorting a collection based on the following comparator.我正在根据以下比较器对集合进行排序。

public static Comparator<MyClass> CMP_TIME_DESC = new Comparator<MyClass>() {
    @Override
    public int compare(MyClass o1, MyClass o2) {
        return o2.getOrderSendTime().compareTo(o1.getOrderSendTime());
    }
};

The values are always non-null.这些值总是非空的。 And the getOrderSendTime() object is of the java.util.Date class. getOrderSendTime() 对象属于 java.util.Date 类。

I understand that this is a transitivity inconsistency, and I would assume a class like this would not have such issues.我知道这是传递性不一致,我认为这样的类不会有这样的问题。 I searched for open issues, but did not find any on the topic.我搜索了未解决的问题,但没有找到有关该主题的任何问题。

Any ideas?有任何想法吗?

Your issue is related to this one: Sort algorithm changes in Java 7您的问题与此有关: Java 7 中的排序算法更改

It happens because the default sort algorithm has changed from MergeSort to TimSort .发生这种情况是因为默认排序算法已从 MergeSort 更改为 TimSort

One workaround is to add -Djava.util.Arrays.useLegacyMergeSort=true to the JVM environment.一种解决方法是将-Djava.util.Arrays.useLegacyMergeSort=true添加到 JVM 环境。

The best option is to conform to the comparison general contract but I think you didn't provide enough information in your question for this.最好的选择是遵守比较一般合同,但我认为您在问题中没有为此提供足够的信息。

I had this same exception, and it happened when I had java.util.Date and java.sql.Timestamp objects in the same list/array when being sorted, running on Java8.我有同样的异常,当我在 Java8 上运行时在同一个列表/数组中有java.util.Datejava.sql.Timestamp对象时发生了这种情况。 (This mix was due to some objects being loaded from database records with the Timestamp data type, and others being created manually, and the objects having only a Date object in them.) (这种混合是由于某些对象是从具有Timestamp数据类型的数据库记录中加载的,而其他对象是手动创建的,并且这些对象中只有一个Date对象。)

The exception also doesn't happen every time you sort the same data set, and it seems that there also have to be at least 32 of these mixed objects in the array for it to occur.每次对同一数据集进行排序时也不会发生异常,而且似乎数组中至少必须有 32 个这些混合对象才能发生。

If I use the legacy sort algorithm, this also doesn't occur (see how in Ortomala Lokni's answer).如果我使用传统排序算法,这也不会发生(请参阅 Ortomala Lokni 的回答中的方法)。

This also doesn't happen if you use only java.util.Date objects or only java.sql.Timestamp objects in the array.如果在数组中仅使用java.util.Date对象或仅使用java.sql.Timestamp对象,则也不会发生这种情况。

So, the issue seems to be TimSort combined with the compareTo methods in java.util.Date and java.sql.Timestamp .因此,问题似乎是TimSortjava.util.Datejava.sql.Timestamp的 compareTo 方法相结合。

However, it didn't pay for me to research why this is happening since it is fixed in Java 9!但是,我没有为研究为什么会发生这种情况而付出代价,因为它已在 Java 9 中修复!

As a workaround until Java9 is released and we can get our systems updated, we have manually implemented a Comparator that only uses getTime() .作为 Java9 发布之前的一种解决方法,我们可以更新我们的系统,我们手动实现了一个仅使用getTime()Comparator This seems to work fine.这似乎工作正常。

Here is code that can be used to reproduce the issue:以下是可用于重现该问题的代码:

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);
        }
    }
}

Edit: I have removed the exception expectation so you can SEE it throwing when run.编辑:我已经删除了异常期望,所以你可以看到它在运行时抛出。

将“-Djava.util.Arrays.useLegacyMergeSort=true”添加到 VM 参数。

Faced this problem today, after spending a few hours, realized that I was comparing Longs.今天面对这个问题,花了几个小时后,意识到我在比较多头。 Instead, you need to compare Long.longValue().相反,您需要比较 Long.longValue()。

MyData.utcTime() returns Long. MyData.utcTime() 返回 Long。 So instead of:所以而不是:

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;
    }
};

I used, the following to fix the problem.我使用了以下内容来解决问题。

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;
    }
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Java 7:java.lang.IllegalArgumentException:比较方法违反了其一般合同 - Java 7 : java.lang.IllegalArgumentException: Comparison method violates its general contract java.lang.IllegalArgumentException:比较方法违反了它的一般约定,在 java7 中给出了错误 - java.lang.IllegalArgumentException: Comparison method violates its general contract giving Error in java7 Java sort抛出java.lang.IllegalArgumentException:比较方法违反了其一般合同 - Java sort throws java.lang.IllegalArgumentException: Comparison method violates its general contract Java 错误:java.lang.IllegalArgumentException:比较方法违反其一般约定 - Java Error: java.lang.IllegalArgumentException: Comparison method violates its general contract Java Rest Template throws java.lang.IllegalArgumentException: Comparison method violates its general contract - Java Rest Template throws java.lang.IllegalArgumentException: Comparison method violates its general contract 错误:java.lang.IllegalArgumentException:即使使用替代方法,比较方法也违反了其常规协定 - Error: java.lang.IllegalArgumentException: Comparison method violates its general contract even using workaround 为什么我得到这个异常 java.lang.IllegalArgumentException:比较方法违反了它的一般契约 - Why did I get this exception java.lang.IllegalArgumentException: Comparison method violates its general contract 随机错误-java.lang.IllegalArgumentException:比较方法违反了其一般约定 - Random error - java.lang.IllegalArgumentException: Comparison method violates its general contract 获取java.lang.IllegalArgumentException:比较方法违反了其一般约定! 排序算法应该是100%稳定的 - Getting java.lang.IllegalArgumentException: Comparison method violates its general contract! with a sort algo that should be 100% stable 线程“AWT-EventQueue-0”中的异常java.lang.IllegalArgumentException:比较方法违反了其总契约 - Exception in thread “AWT-EventQueue-0” java.lang.IllegalArgumentException: Comparison method violates its general contract
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM