java-collections.sort异常Comparison method violates its general contract!

异常信息

java.lang.IllegalArgumentException: Comparison method violates its general contract!
 at java.util.TimSort.mergeHi(TimSort.java:868)
  at java.util.TimSort.mergeAt(TimSort.java:485)
  at java.util.TimSort.mergeCollapse(TimSort.java:408)
at java.util.TimSort.sort(TimSort.java:214)
  at java.util.TimSort.sort(TimSort.java:173)
  at java.util.Arrays.sort(Arrays.java:659)
  at java.util.Collections.sort(Collections.java:217)
...

原因

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

if (len2 == 0) {
    throw new IllegalArgumentException("Comparison method violates its general contract!");
}
  关于1.7下Arrays.sort(Object[] a)的实现:

    public static void sort(Object[] a) {  
            if (LegacyMergeSort.userRequested)  
                legacyMergeSort(a);  
            else  
                ComparableTimSort.sort(a);  
        }  
        /** To be removed in a future release. */  
        private static void legacyMergeSort(Object[] a) {  
            Object[] aux = a.clone();  
            mergeSort(aux, a, 0, a.length, 0);  
        }  
 而1.5下Arrays.sort(Object[] a)的实现:

    public static void sort(Object[] a) {  
            Object[] aux = (Object[])a.clone();  
            mergeSort(aux, a, 0, a.length, 0);  
        }  
DK6到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

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

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

正确方式:

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

解决方案:

执行Collections.sort进行排序前可以调用:

System.setProperty("java.util.Arrays.useLegacyMergeSort", "true"); 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值