【开发经验】java list.sort的坑

异常信息

Format: Comparison method violates its general contract!
Params: null
StackTrace: java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:899)
at java.util.TimSort.mergeAt(TimSort.java:516)
at java.util.TimSort.mergeCollapse(TimSort.java:441)
at java.util.TimSort.sort(TimSort.java:245)
at java.util.Arrays.sort(Arrays.java:1512)
at java.util.ArrayList.sort(ArrayList.java:1454)
at

如何复现

下面的代码看似没什么问题,可以多执行几次,或者将循环32次调高一点。50次 100次。然后就会报同样的错误。

import java.util.*;

public class TestList {
    public static void main(String[] args) {
    	//随机产生32个[0~3]的数字集合
        Random random = new Random();
        ArrayList<Integer> list = new ArrayList<>();
        //这里为什么是32?
        for (int i = 0; i < 32; i++) {
            list.add(random.nextInt(4));
        }
        System.out.println(list);
        list.sort((o1, o2) -> {
        	//定义一个不具备自反性的Comparator
            if(o1>o2){
                return 1;
            }
            return -1;
        });

        System.out.println(list);
    }
}

解决方案

sort里面通过Comparatorcomparing、comparingInt、comparingLong、comparingDouble等方法代替,不要手动去返回1、-1、0。 如

list.sort(Comparator.comparingInt(User::getSort))

或者判断的时候这样写,也不会报错。

list.sort((o1, o2) -> {
            if(o1>o2){
                return 1;
            }
            if(o1

结论

​ 好了,看到这里你的问题已经解决了,可以静下心来看一看异常原因了。因为排序算法要求比较器Comparator满足:

  1. 自反性

  2. 传递性

  3. 对称性

三个条件的约束,好像没太懂?

        简单看来,作为一个比较器来说,以上3个要求似乎合情合理,理所当然,但事实上,开发者很容易忽略一些特定的情况,因为以上3个要求对于排序来讲,并不是全部必要的。

        换句话说,我们必须要处理得当,同时返回-1、0、1这三个变量。如果少了,在数据量小的情况下也许不会报错,在数据足够多,足够极端的情况下就会报错。 Collections.sort()在排序算法上的更新固然能够带来排序性能上的提升,但这一次排序算法的升级对比较器Comparator增加了一些规则,并没有完全向前兼容,更由于增加的规则是隐性的,这就使得开发人员在无意之间制造了线上环境“万万想不到”的异常,甚至造成线上环境的崩溃,产生损失。在一定的程度上甚至可以说,这一升级是得不偿失的。

你可能感兴趣的:(java开发,java,jvm,sort,排序)