Comparison method violates its general contract排序报错

Comparison method violates its general contract报错

场景

今天在安安心心的敲着代码,安逸的思考着业务逻辑,突然就被测试的紧急呼叫给打破,原来是客户现场的生产环境出现问题了,通过日志的定位才发现是排序的问题。明明代码上线很久了,通过提交记录也没有发现有相关代码的修改,那到底是什么情况呢?通过下面我们来了解一下。

异常描述

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

异常出现情况

Collections.sort(list, new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o1.getAge() - o2.getAge();
            }
        });
Collections.sort(list, new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o1.getAge() > o2.getAge() ? 1 : -1;
            }
        } );

原因分析

JDK7及以上版本中的sort函数实现变了,与旧版本的不同,存在兼容问题了,导致有些使用旧版本的写法可能会出现问题。在开发过程或者测试过程当中没有出现问题,但是到了生产环境有可能就会出现报错。

当x == y时,sgn(compare(x, y)) = -1,-sgn(compare(y, x)) = 1,这违背了sgn(compare(x, y)) == -sgn(compare(y, x))约束
新版本中对比较有约束条件,如果违反了约束条件就会抛出llegalArgumentException异常,JDK6中则忽略了这种情况,那么新的约束是啥子?

sgn(compare(x, y)) == -sgn(compare(y, x))
((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0
compare(x, y)==0 implies that sgn(compare(x, z))==sgn(compare(y, z)) for all z
所以上面的代码就存在问题,运行过程当中可能就会出现这个报错。大家一定要注意啊,这个写法出现问题,并不一定就会出现报错,不能以报错来判别代码的写法是否有问题,有可能在开发测试甚至是生产上运行都一直没有问题,然后突然一天就出现问题了,并且错误还很难进行复现。

解决办法

  1. 增加jvm启动参数 -Djava.util.Arrays.useLegacyMergeSort=true
  2. 修改排序写法
Collections.sort(list, new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                int i = o1.getAge().compareTo(o2.getAge());
                return -i;
            }
        });
Collections.sort(list, new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o1.getAge() >= o2.getAge() ? 1 : -1;
            }
        } );

结语

大家平时在开发过程当中一定要注意这个问题,因为这个问题并不一定会暴露在你的开发和测试过程当中,等部署在生产的时候,就等于埋了一个雷,指不定哪天就暴雷了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值