Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
java.lang.IllegalArgumentException:比较方法违反了它的一般约定!日期类型_Java_Sorting_Date_Timsort - Fatal编程技术网

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

java.lang.IllegalArgumentException:比较方法违反了它的一般约定!日期类型,java,sorting,date,timsort,Java,Sorting,Date,Timsort,我正在根据以下比较器对集合进行排序 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(TimSor

我正在根据以下比较器对集合进行排序

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)
公共静态比较器CMP\u TIME\u DESC=新比较器(){
@凌驾
公共整数比较(MyClass o1,MyClass o2){
返回o2.getOrderSendTime().compareTo(o1.getOrderSendTime());
}
};
这些值总是非空的。 getOrderSendTime()对象属于java.util.Date类

我知道这是一个传递性不一致的问题,我假设这样的类不会有这样的问题。我搜索了公开的问题,但没有找到任何关于这个主题的


有什么想法吗?

您的问题与此相关:

发生这种情况是因为默认的排序算法已被修改

一种解决方法是向JVM环境添加
-Djava.util.Arrays.useLegacyMergeSort=true


最好的选择是遵守比较总合同,但我认为您在问题中没有为此提供足够的信息

我也有同样的异常,当我在Java8上运行排序时,在同一个列表/数组中有
java.util.Date
java.sql.Timestamp
对象时,就会发生这种异常。(这种混合是由于一些对象是从带有
时间戳
数据类型的数据库记录加载的,而其他对象是手动创建的,并且这些对象中只有
日期
对象。)

也不是每次对同一数据集进行排序时都会发生异常,而且似乎数组中还必须至少有32个这样的混合对象才能发生异常

如果我使用传统的排序算法,这也不会发生(请参见Ortomala Lokni的答案中的说明)

如果在数组中仅使用
java.util.Date
对象或仅使用
java.sql.Timestamp
对象,也不会发生这种情况

因此,问题似乎是
TimSort
java.util.Date
java.sql.Timestamp
中的compareTo方法相结合

但是,我没有研究为什么会发生这种情况,因为它在Java 9中是固定的

在Java9发布之前,作为一种变通方法,我们可以更新我们的系统,我们已经手动实现了一个只使用
getTime()
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());
    }
};
导入java.sql.Timestamp;
导入java.util.ArrayList;
导入java.util.Collections;
导入java.util.Date;
导入java.util.List;
导入org.junit.Test;
公共类TIMSORTDATE和TIMESTATEST测试{
//具有所有日期、所有时间戳、所有字符串或所有长度的相同测试数据不会失败。
//仅在时间戳和日期对象混合时失败
@试验
public void testSortWithTimestampsAndDatesFails()引发异常{
列表日期=新建ArrayList();
添加(新时间戳(1498621254602L));
添加(新时间戳(1498621254603L));
添加(新时间戳(1498621254603L));
添加(新时间戳(1498621254604L));
添加(新时间戳(1498621254604L));
添加(新时间戳(1498621254605L));
添加(新时间戳(1498621254605L));
添加(新时间戳(1498621254605L));
添加(新时间戳(1498621254605L));
添加(新时间戳(1498621254606L));
添加(新时间戳(1498621254607L));
添加日期(新日期(1498621254605L));
添加(新时间戳(1498621254607L));
添加(新时间戳(1498621254609L));
添加日期(新日期(1498621254603L));
添加日期(新日期(1498621254604L));
添加日期(新日期(1498621254605L));
添加日期(新日期(1498621254605L));
添加日期(新日期(1498621254607L));
添加(新时间戳(1498621254607L));
添加日期(新日期(1498621254608L));
添加(新时间戳(1498621254608L));
添加日期(新日期(1498621254611L));
添加(新时间戳(1498621254612L));
添加(新时间戳(1498621254613L));
添加日期(新日期(1498621254607L));
添加(新时间戳(1498621254607L));
添加(新时间戳(1498621254608L));
添加(新时间戳(1498621254609L));
添加(新时间戳(1498621254611L));
添加日期(新日期(1498621254603L));
添加日期(新日期(1498621254606L));
对于(int i=0;i<200;i++){
收藏。洗牌(日期);
集合。排序(日期);
}
}
}

编辑:我已经删除了异常预期,因此您可以看到它在运行时抛出。

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

今天遇到这个问题,花了几个小时后,意识到我在比较长。相反,您需要比较Long.longValue()

MyData.utcTime()返回Long。因此,不是:

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);
        }
    }
}
public static Comparator sortByUtcPublishedDesc=new Comparator(){
@凌驾
公共整数比较(MyData n1,MyData n2){
如果(n2.utcTime()n1.utcTime())
返回1;
}
};
我使用以下方法来解决这个问题

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 sortByUtcPublishedDesc=new Comparator(){
@凌驾
公共整数比较(MyData n1,MyData n2){
如果(n2.utcTime().longValue()n1.utcTime())
返回1;
}
};

您是否绝对确定在排序过程中没有其他线程(或者只是
getOrderSendTime()
中的一些计算会产生副作用)修改日期?是的,对象是ob
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;
    }
};