首页 > 解决方案 > 如何解决 Java Collections.sort() 比较方法违反其一般约定异常

问题描述

我正在使用 Collections.sort 根据时间字段按升序对列表进行排序。下面是代码

private String getShipmentInpickingTime(List<Shipments> shipments) {
        logger.info("in getShipmentInpickingTime");
        DateFormat sdf = new SimpleDateFormat("hh:mm");

        Collections.sort(shipments, (o1, o2) -> {
            try {
                if ((!"null".equals(o1.getShipmentinpickingtime())
                        && !StringUtils.isEmpty(o1.getShipmentinpickingtime()))
                        && (!"null".equals(o2.getShipmentinpickingtime())
                                && !StringUtils.isEmpty(o2.getShipmentinpickingtime()))) {
                    return sdf.parse(o1.getShipmentinpickingtime()).compareTo(sdf.parse(o2.getShipmentinpickingtime()));
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
            int count1 = 0;
            return count1;
        });

这个方法抛出异常——

java.lang.IllegalArgumentException: Comparison method violates its general contract.

关于这个问题,我浏览了谷歌 - 它说我正在将更大的对象与更小的对象进行比较。我尝试颠倒对象的顺序,但没有运气。

标签: javaspringsortingcollectionscomparator

解决方案


如果任何一个元素无法解析,您只捕获一次异常。

考虑以下时间的三批货物:
A - 12:34
B - 34:56
C - null

使用您的比较器,compare(A, C)将返回 0,compare(B, C)将返回 0,但compare(A, B)将返回非零结果,从而违反了传递性的一般合同。

一种简单的方法是使用Comparator.comparing语法分别解析每个元素:

DateFormat sdf = new SimpleDateFormat("hh:mm");

shipments.sort(Comparator.comparing(
                   Shipments::getShipmentinpickingtime, 
                   Comparator.nullsLast(Comparator.comparing(time -> {
                       try {
                           if (!"null".equals(time) && !StringUtils.isEmpty(time)) {
                               return sdf.parse(time);
                           }
                       } catch (ParseException ignoe) {
                           // Not a valid time
                       }
                       return null;
                   })))
              );

推荐阅读