无法复制:“比较方法违反了其一般合同!”

我收到以下错误:“比较方法违反了它的一般约定!” 当使用以下比较器时,但是我无法使用jUnit复制异常。我想知道是什么引起了这个问题以及如何复制它。有一些其他例子也有相同的问题,但没有类似的例子。

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;

}

}

通过使用以下代码调用该代码:

``

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

```

谢谢你的帮助。

额外信息:该错误似乎发生在Java utils中的TimSort类中,以及发生在称为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

回答:

来自的文档compare

实施者必须确保sgn(x.compareTo(y)) == -sgn(y.compareTo(x))所有人x和y

基于减法的比较器不满足此条件。这是因为减法会溢出。例如

Integer.MIN_VALUE - 0

0 - Integer.MIN_VALUE

都是负面的。

您处理Dates的方式也有问题。从以下文档中compare:

最后,实现者必须确保x.compareTo(y)==0暗示sgn(x.compareTo(z)) == sgn(y.compareTo(z))所有z。

您的compare方法打破了这一点。例如,如果x是null,y是1970年1月1日,并z为1970年1月2日,然后

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

}

我设法重现了这个问题,但List至少只持续了s个32。请参阅此链接以获取为什么List至少32需要一个大小a的解释。为什么使用Collections.sort的该程序仅对大小为32或更大的列表失败?

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;

}

}

}

}

}

以上是 无法复制:“比较方法违反了其一般合同!” 的全部内容, 来源链接: utcz.com/qa/406546.html

回到顶部