Collectons.sort的坑

发布时间 2023-11-09 09:43:43作者: 忧伤还是快乐EL
[Request processing failed; nested exception is java.lang.IllegalArgumentException: Comparison method violates its general contract!] with root cause
 java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.TimSort.mergeLo(Unknown Source)
    at java.util.TimSort.mergeAt(Unknown Source)
    at java.util.TimSort.mergeCollapse(Unknown Source)
    at java.util.TimSort.sort(Unknown Source)
    at java.util.Arrays.sort(Unknown Source)
    at java.util.ArrayList.sort(Unknown Source)
    at java.util.Collections.sort(Unknown Source)

以上是报错。

 

具体代码如下:

 Collections.sort(data, new Comparator<Map<String, Object>>() {
            @Override
            public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                String o1Bbm1 = CourtUtils.trim(o1.get("CBBM1"));
                String o2Bbm1 = CourtUtils.trim(o2.get("CBBM1"));
                TDepart tDepart1 = CacheUtils.getTDepart(o1Bbm1);
                TDepart tDepart2 = CacheUtils.getTDepart(o2Bbm1);
                if ("".equals(o1Bbm1) || tDepart1 == null) {
                    return 1;
                }
                if ("".equals(o2Bbm1) || tDepart2 == null) {
                    return -1;
                }
                Integer pxh0 = tDepart1.getPxh() == null ? 0 : tDepart1.getPxh();
                Integer pxh1 = tDepart2.getPxh() == null ? 0 : tDepart2.getPxh();
                if (pxh0 == pxh1) {
                    return o1Bbm1.compareTo(o2Bbm1);
                } else {
                    return pxh0 - pxh1;
                }
            }
        });

在对list进行排序时,报错。但是正是环境上是没问题的。所以要排查兼容测试环境的问题,防止正式环境报错。

 

首先要知道,在 JDK7 版本以上,Comparator 要满足自反性,传递性,对称性,不然 Arrays.sort,Collections.sort 会报 IllegalArgumentException 异常。

自反性:当 两个相同的元素相比时,compare必须返回0,也就是compare(o1, o1) = 0;

反对称性:如果compare(o1,o2) = 1,则compare(o2, o1)必须返回符号相反的值也就是 -1;

传递性:如果 a>b, b>c, 则 a必然大于c。也就是compare(a,b)>0, compare(b,c)>0, 则compare(a,c)>0。

最容易出问题的,就是传递性。比如:

假设存在三个元素:stu1, null,stu2,则
compare(stu1, null)= 0,
compare(null, stu2) = 0,
compare(stu1,stu2) =1 很明显违反了传递性原则。

那么,咋改呢?

多进行一次判断,就可以。

Collections.sort(data, new Comparator<Map<String, Object>>() {
            @Override
            public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                String o1Bbm1 = CourtUtils.trim(o1.get("CBBM1"));
                String o2Bbm1 = CourtUtils.trim(o2.get("CBBM1"));
                TDepart tDepart1 = CacheUtils.getTDepart(o1Bbm1);
                TDepart tDepart2 = CacheUtils.getTDepart(o2Bbm1);
                if ("".equals(o1Bbm1) || tDepart1 == null) {
                    if ("".equals(o2Bbm1) || tDepart2 == null) {
                        return 0;
                    }
                    return 1;
                }
                if ("".equals(o2Bbm1) || tDepart2 == null) {
                    return -1;
                }
                Integer pxh0 = tDepart1.getPxh() == null ? 0 : tDepart1.getPxh();
                Integer pxh1 = tDepart2.getPxh() == null ? 0 : tDepart2.getPxh();
                if (pxh0 == pxh1) {
                    return o1Bbm1.compareTo(o2Bbm1);
                } else {
                    return pxh0 - pxh1;
                }
            }
        });

 

完活。