无法复制:“比较方法违反了其一般合同! [英] Unable to replicate : "Comparison method violates its general contract!"

查看:128
本文介绍了无法复制:“比较方法违反了其一般合同!的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我收到以下错误:比较方法违反了其一般合同!当使用以下比较器时,但是我无法使用jUnit复制异常。我想知道是什么导致了这个问题,以及如何复制它。

I receive the following error: "Comparison method violates its general contract!" when using the following comparator, however I am unable to replicate the exception using jUnit. I'd like to know what caused this issue and how to replicate it. There are examples of others having the same problem but not how to replicate it.

public class DtoComparator implements Comparator<Dto> {

    @Override
    public int compare(Dto r1, Dto r2) {

        int value = 0;

        value = r1.getOrder() - r2.getOrder();

        if (value == 0 && !isValueNull(r1.getDate(), r2.getDate()))
            value = r1.getDate().compareTo(r2.getDate());

        return value;
    }

    private boolean isValueNull(Date date, Date date2) {
        return date == null || date2 == null;
    }
}

使用以下命令调用代码:

The code is called by using:

Collections.sort(dtos, new DtoComparator());

感谢任何帮助。

info:
错误似乎发生在Timsort类里面Java utils和一个名为mergeLo的方法。
链接: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/TimSort .java#TimSort.mergeLo%28int%2Cint%2Cint%2Cint%29

推荐答案

code>比较。

From the documentation of compare.


实现者必须确保 sgn所有 x y code>

基于减法的比较器不符合此条件。这是因为减法可能溢出。例如

Subtraction-based comparators do not meet this condition. This is because the subtraction can overflow. For example

Integer.MIN_VALUE - 0
0 - Integer.MIN_VALUE 

都是否定的。

日期。从比较的文档:


最后,实现者必须确保 x.compareTo(y)== 0 意味着 sgn(x.compareTo(z))== sgn(y.compareTo(z)),所有 z

$ c> compare 方法打破此。例如,如果 x null y 1970年1月和 z 是1970年1月2日,然后

Your compare method breaks this. For example, if x is null, y is January 1st 1970 and z is January 2nd 1970, then

compare(x, y) == 0  // x == null
compare(x, z) == 0  // x == null
compare(y, z) == -1 // January 1st is before January 2nd.

我写的方法如下:

@Override
public int compare(Dto r1, Dto r2) {

    int value = Integer.compare(r1.getOrder(), r2.getOrder());
    if (value != 0)
        return value;
    Date date1 = r1.getDate();
    Date date2 = r2.getDate();
    if (date1 == null && date2 == null)
        return 0;
    if (date1 == null)
        return -1;
    if (date2 == null)
        return 1;
    return date1.compareTo(date2);
} 



我设法重现了这个问题,但只有列表的长度至少 32 。请参阅此链接,以了解为什么需要列表大小至少 32 为什么使用Collections.sort的程序只对大小为32或更大的列表失败?

I have managed to reproduce the problem, but only for Lists of length at least 32. See this link for an explanation of why a List of size at least 32 is required. Why does this program using Collections.sort only fail for lists of size 32 or more?

public class Main {

    private static final class NumAndDate {
        private final int num;
        private final Date date;

        NumAndDate(int num, Date date) {
            this.num = num;
            this.date = date;
        }
    }

    public static final class NumAndDateComparator implements Comparator<NumAndDate> {

        @Override
        public int compare(NumAndDate r1, NumAndDate r2) {

            int value = 0;

            value = r1.num - r2.num;

            if (value == 0 && !isValueNull(r1.date, r2.date))
                value = r1.date.compareTo(r2.date);

            return value;
        }

        private boolean isValueNull(Date date, Date date2) {
            return date == null || date2 == null;
        }
    }

    public static void main(String[] args) {
        NumAndDate[] array = {
                new NumAndDate(0, new Date(0)),
                new NumAndDate(0, new Date(1)), 
                new NumAndDate(0, null)
        };
        Random random = new Random();
        for (int i = 0; i < 100; i++) {
            for (int j = 0; j < 10000; j++) {
                List<NumAndDate> list = new ArrayList<>();
                int[] arr = new int[i];
                for (int k = 0; k < i; k++) {
                    int rand = random.nextInt(3);
                    arr[k] = rand;
                    list.add(array[rand]);
                }
                try {
                    Collections.sort(list, new NumAndDateComparator());
                } catch (Exception e) {
                    System.out.println(arr.length + " " + Arrays.toString(arr));
                    return;
                }
            }
        }
    }
}

这篇关于无法复制:“比较方法违反了其一般合同!的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆