在对集合进行排序时出现以下错误:
Caused by: java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeLo(TimSort.java:777)
at java.util.TimSort.mergeAt(TimSort.java:514)
at java.util.TimSort.mergeCollapse(TimSort.java:441)
at java.util.TimSort.sort(TimSort.java:245)
这是比较器和使用它的流。
Comparator<Task> comparator = comparing(Task::getAssigneeSite, nullsLast(naturalOrder())).thenComparing(Task::getDueDate,
nullsLast(naturalOrder()));
Collection<Task> groupTasks = findTasks(site, dossierAdministratorGroup).stream()
.sorted(comparator)
.collect(toList());
我找到了一个类似问题的答案:
异常& # 39;比较法违反它的总承包合同! & # 39;比较对象的两个日期属性
但我不明白这怎么能解决问题。只有当bean本身可以为空时,才有用将比较器包装为空,而事实并非如此(任务永远不会为空)。
在我的理解中,对于assignesite比较器中的'nullsLast(…)'意味着null应该被认为大于' assignesite '对象,DueDate也是如此。所以我不知道是什么违反了合同。
谁能解释这个比较器内部发生的契约违反?
所以,这对我来说可能是非常愚蠢的,但问题是在'Site'类中已经存在的比较器中,我没有验证。
@Override
public int compareTo(Site other) {
if (this.code < other.getCode()) {
return -1;
} else {
return 1;
}
}
这里有一个明显的问题,因为比较器没有指定两个代码字段相等的情况。除此之外,它也不考虑任何整数对象可能为空。
正确的null安全实现(使用java 8的comparator . compare方法)应该是:
return comparing(Site::getCode, nullsLast(naturalOrder())).compare(this, other);
我把这个答案放在这里是为了提醒其他人在遇到合同违反错误时检查所有的比较器。