Comparison method violates its general contract!
2015-11-24 14:27
363 查看
版权声明:本文为博主原创文章,转载请注明出处http://blog.csdn.net/ghsau。
目录(?)[+]
[java]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 > o2 ? 1 : -1;// 错误的方式
}
});
[java]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
// return o1 > o2 ? 1 : -1;
return o1.compareTo(o2);// 正确的方式
}
});
[plain]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
-Djava.util.Arrays.useLegacyMergeSort=true
这样就会照旧使用JDK6的排序算法,在不能修改代码的情况下,解决这个兼容的问题。
[plain]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
Area: API: Utilities
Synopsis: Updated sort behavior for Arrays and Collections may throw an IllegalArgumentException
Description: 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: behavioral
RFE: 6804124
描述的意思是说,java.util.Arrays.sort(java.util.Collections.sort调用的也是此方法)方法中的排序算法在JDK7中已经被替换了。如果违法了比较的约束新的排序算法也许会抛出llegalArgumentException异常。JDK6中的实现则忽略了这种情况。那么比较的约束是什么呢?看这里,大体如下:
![](https://img-blog.csdn.net/20141218224145015?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2hzYXU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
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
再回过头来看我们开篇有问题的实现:
[java]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
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中抛出了本文标题的异常。
[java]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
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};
(完)
目录(?)[+]
背景
16号为了统一线上服务器运行环境,将两台服务器的Tomcat6+JDK6升级到Tomcat7+JDK7,本以为很简单的事情,升级后自己验证也没问题,没想到却悲剧了。升级后,过了半小时运营就找过来反馈问题,部分角色无法登陆系统,由于异常日志没有输出,没有找到问题,无奈回滚。今天我们就来说说JDK6升级到JDK7会遇到的坑。本文为了方便搜索,就直接以异常信息作为文章标题了。复现
回滚后,到beta环境按照线上的权限配置,复现该问题,加上了error日志输出,输出了文章标题的异常,这个异常是在类似如下代码中抛出的:[java]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 > o2 ? 1 : -1;// 错误的方式
}
});
解决方案
先说如何解决,解决方式有两种。修改代码
上面代码写的本身就有问题,第4行没有考虑o1 == o2的情况,再者说我们不需要自己去比较,修改为如下代码即可:[java]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
// return o1 > o2 ? 1 : -1;
return o1.compareTo(o2);// 正确的方式
}
});
不修改代码
那么问题来了。为什么上面代码在JDK6中运行无问题,而在JDK7中却会抛异常呢?这是因为JDK7底层的排序算法换了,如果要继续使用JDK6的排序算法,可以在JVM的启动参数中加入如下参数:[plain]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
-Djava.util.Arrays.useLegacyMergeSort=true
这样就会照旧使用JDK6的排序算法,在不能修改代码的情况下,解决这个兼容的问题。
分析
在我以前的认知中,高版本的JDK是可以兼容之前的代码的,与同事讨论了一番另加搜索了一番,事实证明,JDK6到JDK7确实存在兼容问题(不兼容列表)。在不兼容列表中我们可以找到关于Collections.sort的不兼容说明,如下:[plain]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
Area: API: Utilities
Synopsis: Updated sort behavior for Arrays and Collections may throw an IllegalArgumentException
Description: 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: behavioral
RFE: 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
再回过头来看我们开篇有问题的实现:
[java]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
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。后面文章会分析TimSort。本文给出一个会引发该异常的Case,以便有心人共同研究,如下:[java]
view plaincopyprint?
![](https://code.csdn.net/assets/CODE_ico.png)
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};
(完)
相关文章推荐
- 了解和配置 PAM
- JdbcOperations 综合
- pigeon物联网平台- developer portal web服务设计及实现
- 面试题(十二)
- Qt Creator中常用的快捷键总结
- 11/24 初学网页设计
- 微软宣布Win7/8.1考证日期从2016年1月31日延至2016年7月31日
- 快速对齐你的BarTender条码
- 数据索引---Solr DIH
- windows 10 及 windows server 2012 中vnc不显示鼠标光标的问题解决
- Linux发行版deepin及其软件包管理
- 十六进制转八进制
- ServletConfig和ServletContext的区别及应用
- 自写的非常不错的oracle语句 精选
- (转)RedHat9详细安装图解
- Win10运行在哪里,Win10的运行怎么打开
- Spring3 MVC 深入研究
- Jquery ajax加载等待执行结束再继续执行下面代码操作
- 图像金字塔
- 设计模式 - 行为型模式 - 备忘录模式