Java对List对象排序Comparator实现接口发生异常- Comparison method violates its general contract!

9 篇文章 0 订阅
5 篇文章 0 订阅

异常场景

在JDK8环境下,通过实现Comparator接口,对HashMap根据value降序排序

 

出异常的Comparator

        List<MenuInfo> menus = new ArrayList<>();
        menuInfos.stream().forEach(menuInfo -> {
            if (!menus.contains(menuInfo)){
                menus.add(menuInfo);
            }
        });
        return menus.stream().sorted(new Comparator<MenuInfo>() {
            @Override
            public int compare(MenuInfo o1, MenuInfo o2) {
                if (o1.getType() - o2.getType() == 0)
                    if ((o1.getPid() - o2.getPid()) == 0)
                        return o1.getZindex() - o2.getZindex();
                return o1.getType() - o2.getType();
            }
        }).collect(toList());

异常信息

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

 

异常原因

JDK7/JDK8的Collections.Sort方法实现中,如果两个值是相等的,那么compare方法需要返回0,否则 **可能** 会在排序时抛错,而JDK6是没有这个限制的。

不同版本JDK中Comparator约束差异

在 JDK7/JDK8(当前JDK8),Comparator 要满足自反性、传递性、对称性,不然 Arrays.sort,Collections.sort 会报 IllegalArgumentException 异常。(JDK7 Comparator,JDK8 Comparator)

说明:

1) 自反性:x,y 的比较结果和 y,x 的比较结果相反。

2) 传递性:x>y,y>z,则 x>z。

3) 对称性:x=y,则 x,z 比较结果和 y,z 比较结果相同。

Comparator在实现时需要遵照以下约束:

根据约束Comparator实现做如下修改:

 List<MenuInfo> menus = new ArrayList<>();
        menuInfos.stream().forEach(menuInfo -> {
            if (!menus.contains(menuInfo)){
                menus.add(menuInfo);
            }
        });
        return menus.stream().sorted(new Comparator<MenuInfo>() {
            @Override
            public int compare(MenuInfo o1, MenuInfo o2) {
                
                        return  o1.getZindex() < o2.getZindex() ? -1 : (o1.getZindex() == o2.getZindex()) ? 0 : 1;
         
            }
        }).collect(toList());

 

在JDK7/JDK8文档中对Comparator实现虽然说不严格要求遵循约束,比方说上述出异常的Comparator,在执行时不一定会报异常,但是为了程序稳定性,最好是遵循约束。至于JDK7之后的Comparator底层排序实现算法Timsort原理,可阅读以下几篇文章:

Timsort原理介绍

深入理解 timsort 算法

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值