Android Collections.sort()填坑

复现

错误代码如下

Collections.sort(dataList, new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1 > o2 ? 1 : -1;
    }
});

这里看着也没啥问题啊,相同的代码运行在不同手机上为啥有的报错有的不报错呢?根据错误提示Comparison method violates its general contract!去查看源码后找到抛出导致这个错误代码的具体位置

if (len1 == 1) {
    assert len2 > 0;
    System.arraycopy(a, cursor2, a, dest, len2);
    a[dest + len2] = tmp[cursor1];
} else if (len1 == 0) {
    throw new IllegalArgumentException("Comparison method violates its general contract!");
} else {
    assert len2 == 0;
    assert len1 > 1;
    System.arraycopy(tmp, cursor1, a, dest, len1);
}

查阅相关资料后发现说这种写法在Java JDK6中没有问题。在Java JDK6以后,Comparator要满足自反性、传递性、对称性,不然Arrays.sort、Collections.sort会报IllegalArgumentException异常。说明:

  • 自反性:x,y 的比较结果和y,x的比较结果相反。
  • 传递性:x > y,y > z,则x > z。
  • 对称性:x = y,则x,z比较结果和y,z比较结果相同。

然而错误写法:o1 > o2 ? 1 : -1,并没有处理相等的情况,所以在实际使用中可能会出现异常。

斗罗小剧场
小舞:哥,这里我有个疑问了,运行的环境都是Java JDK8的,为啥有的手机不会闪退有的手机会闪退呢?
小三:额......这......
小三:小舞,哥现在修为等级还不够,等我魂力到达90级或许可以帮你解决这个问题!!!

总结

根据上面的分析,在Java JDK6以后,Comparator要满足自反性、传递性、对称性。所以正确的写法应该是

Collections.sort(list, new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
            //return o1 - o2或者return o1.compareTo(o2)
            return o1.compareTo(o2);
    }
});

推荐阅读更多精彩内容