博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Comparison method violates its general contract!
阅读量:6174 次
发布时间:2019-06-21

本文共 2587 字,大约阅读时间需要 8 分钟。

背景

16编号为网上统一server执行环境,他们俩server的Tomcat6+JDK6升级到Tomcat7+JDK7。一想到easy事。升级他们的验证后也没问题,我不认为这悲剧。升级后,一个半小时的手术后找到了反馈问题。部分角色无法登陆。由于没有异常日志输出,有找到问题,无奈回滚。今天我们就来说说JDK6升级到JDK7会遇到的坑。本文为了方便搜索,就直接以异常信息作为文章标题了。

复现

回滚后,到beta环境依照线上的权限配置,复现该问题。加上了error日志输出,输出了文章标题的异常,这个异常是在相似例如以下代码中抛出的:

Collections.sort(list, new Comparator
() { @Override public int compare(Integer o1, Integer o2) { return o1 > o2 ? 1 : -1;// 错误的方式 }});

解决方式

先说怎样解决,解决方式有两种。

改动代码

上面代码写的本身就有问题,第4行没有考虑o1 == o2的情况,再者说我们不须要自己去比較,改动为例如以下代码就可以:

Collections.sort(list, new Comparator
() { @Override public int compare(Integer o1, Integer o2) { // return o1 > o2 ?

1 : -1; return o1 - o2;// 正确的方式 } });

不改动代码

那么问题来了。

为什么上面代码在JDK6中执行无问题,而在JDK7中却会抛异常呢?这是由于JDK7底层的排序算法换了。假设要继续使用JDK6的排序算法,能够在JVM的启动參数中增加例如以下參数:

-Djava.util.Arrays.useLegacyMergeSort=true
这样就会照旧使用JDK6的排序算法,在不能改动代码的情况下,解决这个兼容的问题。

分析

在我曾经的认知中。高版本号的JDK是能够兼容之前的代码的,与同事讨论了一番另加搜索了一番。事实证明,JDK6到JDK7确实存在兼容问题()。在不兼容列表中我们能够找到关于Collections.sort的不兼容说明。例如以下:

Area: API: UtilitiesSynopsis: Updated sort behavior for Arrays and Collections may throw an IllegalArgumentExceptionDescription: The sorting algorithm used by java.util.Arrays.sort and (indirectly) by java.util.Collections.sort has been replaced. The new sort implementation may throw an IllegalArgumentException if it detects a Comparable that violates the Comparable contract. The previous implementation silently ignored such a situation.If the previous behavior is desired, you can use the new system property, java.util.Arrays.useLegacyMergeSort, to restore previous mergesort behavior.Nature of Incompatibility: behavioralRFE: 6804124

描写叙述的意思是说,java.util.Arrays.sort(java.util.Collections.sort调用的也是此方法)方法中的排序算法在JDK7中已经被替换了。假设违法了比較的约束新的排序算法或许会抛出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
再回过头来看我们开篇有问题的实现:
return x > y ?

1 : -1;

当x == y时,sgn(compare(x, y))  = -1。-sgn(compare(y, x)) = 1。这违背了sgn(compare(x, y)) == -sgn(compare(y, x))约束,所以在JDK7中抛出了本文标题的异常。

结论

那么如今能否够盖棺定论了,依照上面的分析来看,使用这样的比較方式(return x > y ? 1 : -1;),仅仅要集合或数组中有同样的元素,就会抛出本文标题的异常。

实则不然,什么情况下抛出异常,还取决于JDK7底层排序算法的实现。也就是大名鼎鼎的。后面文章会分析TimSort。

本文给出一个会引发该异常的Case,以便有心人共同研究,例如以下:

Integer[] array = {0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 2, 1, 0, 0, 0, 2, 30, 0, 3};
      (完)
      本文来自: ,原文地址: 。转载请注明。

版权声明:本文博客原创文章,博客,未经同意,不得转载。

你可能感兴趣的文章
sql注入总结
查看>>
C语言的发展史和特点
查看>>
TurboMai打造邮件系统最高开放性平台
查看>>
Java: I/O(1/3)字节流与字符流的纵向与横向比较
查看>>
关于FlashBuilder使用Starling框架调试运行出错问题(Chrome、Firef...
查看>>
Map遍历的三种方法
查看>>
Eclipse 快捷键
查看>>
SpringDataJPA 多表查询 对象导航查询
查看>>
VMware HA实战攻略之五VMwareHA测试验收
查看>>
Nginx的statua和随机主页配置
查看>>
docker创建私有registry
查看>>
RSYNC实现文件同步
查看>>
C--sizeof
查看>>
开源 java CMS - FreeCMS2.8会员注册
查看>>
Linux里怎样查找文件内容
查看>>
【转载】MapReduce编程 Intellij Idea配置MapReduce编程环境
查看>>
我的友情链接
查看>>
Spring表达式语言SpEL
查看>>
PHP DIRECTORY_SEPARATOR
查看>>
Windows 8 全新安装及初始化
查看>>