zoukankan      html  css  js  c++  java
  • 解决 Comparison method violates its general contract!

    问题:Comparison method violates its general contract!报错

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

    解决方案

    先说如何解决,解决方式有两种。

    修改代码

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

    1 Collections.sort(list, new Comparator<Integer>() {  
    2     @Override  
    3     public int compare(Integer o1, Integer o2) {  
    4         // return o1 > o2 ? 1 : -1;  
    5         return o1.compareTo(o2);// 正确的方式  
    6     }  
    7 });  

    不修改代码

    那么问题来了。为什么上面代码在JDK6中运行无问题,而在JDK7中却会抛异常呢?这是因为JDK7底层的排序算法换了,如果要继续使用JDK6的排序算法,可以在JVM的启动参数中加入如下参数:

    -Djava.util.Arrays.useLegacyMergeSort=true 

    这样就会照旧使用JDK6的排序算法,在不能修改代码的情况下,解决这个兼容的问题。

    分析

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

    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
    再回过头来看我们开篇有问题的实现:
    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,以便有心人共同研究,如下:
    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};  
  • 相关阅读:
    用 Flask 来写个轻博客 (19) — 以 Bcrypt 密文存储账户信息与实现用户登陆表单
    用 Flask 来写个轻博客 (18) — 使用工厂模式来生成应用对象
    用 Flask 来写个轻博客 (18) — 使用工厂模式来生成应用对象
    用 Flask 来写个轻博客 (17) — MV(C)_应用蓝图来重构项目
    用 Flask 来写个轻博客 (17) — MV(C)_应用蓝图来重构项目
    Nginx详解八:Nginx基础篇之Nginx请求限制的配置语法与原理
    Nginx详解七:Nginx基础篇之Nginx官方模块
    Nginx详解六:Nginx基础篇之Nginx日志
    Nginx详解五:Nginx基础篇之HTTP请求
    Nginx详解四:Nginx基础篇之目录和配置语法
  • 原文地址:https://www.cnblogs.com/UniqueColor/p/7484584.html
Copyright © 2011-2022 走看看