java.lang.IllegalArgumentException: Comparison method violates its general contract!

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有了更高的要求:

  1. sgn(compare(x, y)) == -sgn(compare(y, x))—自反性

  2. ((compare(x, y)>0) && (compare(y, z)>0)),则(compare(x, z)>0 — 传递性

  3. 如果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;
        });
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值