java.lang.IllegalArgumentException: Comparison method violates its general contract!
异常报错
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:899)
at java.util.TimSort.mergeAt(TimSort.java:516)
at java.util.TimSort.mergeCollapse(TimSort.java:441)
at java.util.TimSort.sort(TimSort.java:245)
at java.util.Arrays.sort(Arrays.java:1512)
at java.util.ArrayList.sort(ArrayList.java:1462)
产生错误的代码
class Dto{
private int sort;
private Date addTime;
}
ArrayList<Dto> dtos = new ArrayList<>();
//....
dtos.sort((item1, item2) -> {
if ((item1.getAddTime() != null && item2.getAddTime() == null) || (item1.getAddTime() == null || item2.getAddTime() == null)) {
return -1;
}
if (item1.getAddTime().after(item2.getAddTime())) {
return 1;
} else {
return -1;
}
});
原因分析
Collections.sort()在JDK6和JDK7中实现的底层排序算法发生了变化,在JDK6中使用MergeSort排序,而在JDK7中使用TimSort排序。TimSort相比MergeSort具备了更好的性能,但同时也对比较器Comparator有了更高的要求:
-
sgn(compare(x, y)) == -sgn(compare(y, x))—自反性
-
((compare(x, y)>0) && (compare(y, z)>0)),则(compare(x, z)>0 — 传递性
-
如果compare(x, y)==0 那么sgn(compare(x, z))==sgn(compare(y, z)) — 对称性
说明:
1) 自反性:x,y 的比较结果和 y,x 的比较结果相反。
2) 传递性:x>y,y>z,则 x>z。
3) 对称性:x=y,则 x,z 比较结果和 y,z 比较结果相同。
必须要考虑相等的情况:
当x == y时,sgn(compare(x, y)) = -1,-sgn(compare(y, x)) = 1,这违背了sgn(compare(x, y)) == -sgn(compare(y, x))约束,所以在JDK7中抛出了本文标题的异常。
代码修正
dtos.sort((item1, item2) -> {
if(item1.getAddTime() == null && item2.getAddTime() == null)
{
return 0;
}
if (item1.getAddTime() == null)
{
return 1;
}
if (item2.getAddTime() == null)
{
return -1;
}
if (item1.getAddTime().after(item2.getAddTime()))
{
return 1;
}
if (item2.getAddTime().after(item1.getAddTime()))
{
return -1;
}
return 0;
});