1

我正在开发一个旧应用程序,它最初是用 Java 6 编写的,几年前升级到 Java 7。

在这个应用程序中,我使用 Collection.Sortcompare通过实现Comparator接口使用自定义方法对列表进行排序。列表中的对象类型有CompanySchedule3 个属性companyName和。 Scheduleexpirationdate

列表可以包含多个具有相同companyName但具有唯一到期日期的对象。下面的比较函数按公司名称的升序对列表进行排序,并在同一公司名称列表中按到期日期的降序对列表进行排序。下面是方法实现。

    public int compare(CompanySchedule c1, CompanySchedule c2) {
        int returnVal = 0;
        int value = c1.getCompany().getName().compareTo(c2.getCompany().getName());
        if (value == 0){
            if (c1.getUseExpirationDate() == null || c2.getUseExpirationDate() == null){
                returnVal = -1;
            }
            else{
                int chkdate = c1.getUseExpirationDate().compareTo(c2.getUseExpirationDate());
                if (chkdate == 0){
                    returnVal = 0;
                }
                else if (chkdate > 0){
                    returnVal = -1;
                }
                else if (chkdate < 0){
                    returnVal = 1;
                }
            }
        }
        else if (value < 0){
            returnVal = -1;
        }
        else if (value > 0){
            returnVal = 1;
        }


        return returnVal;
    }

我知道在上面的比较方法实现中不满足传递属性时 java.lang.IllegalArgumentException: Comparison method violates its general contract会抛出错误。

有人可以帮助确定此方法在何处违反传递性。谢谢您的帮助。

4

2 回答 2

1

我认为这里有一个问题:

if (c1.getUseExpirationDate() == null || c2.getUseExpirationDate() == null){
                returnVal = -1;
}

如果 a.getUseExpirationDate() == null 并且 b.getUseExpirationDate() == null,你会得到 a < b 和 b < a,这意味着 a < a。

这打破了一致性。这种方法可能存在更多问题,但我没有全部检查。

祝你好运。

编辑

这段代码怎么样?

public int compare(CompanySchedule c1, CompanySchedule c2) {
        int returnVal = 0;
        int value = c1.getCompany().getName().compareTo(c2.getCompany().getName());
        if (value == 0) {
            if (c1.getUseExpirationDate() == null && c2.getUseExpirationDate() != null) {
                returnVal = -1;
            } else if (c1.getUseExpirationDate() != null && c2.getUseExpirationDate() == null) {
                returnVal = 1;
            } else if (c1.getUseExpirationDate() == null && c2.getUseExpirationDate() == null) {
                returnVal = 0;
            } else {
                int chkdate = c1.getUseExpirationDate().compareTo(c2.getUseExpirationDate());
                if (chkdate == 0) {
                    returnVal = 0;
                } else if (chkdate > 0) {
                    returnVal = -1;
                } else if (chkdate < 0) {
                    returnVal = 1;
                }
            }
        } else if (value < 0) {
            returnVal = -1;
        } else if (value > 0) {
            returnVal = 1;
        }


        return returnVal;
    }

为了可比性,我尽量不要对其进行太多更改,但应该对其进行重构。基本上它确定空值小于其他值。

于 2020-02-10T13:36:25.687 回答
1

我知道我迟到了,一旦我找到了我基本上忘记了我问过这个问题的解决方案。所以正如我提到的,该应用程序是用 Java 6 编写的,然后Java 7根据我对 Collections 内部实现的理解升级到 .

Sort 方法将使用的算法从 Merge 排序更改为 Tim Sort,Merge Sort 忽略了 compare 方法实现的 Transitivity 属性,但是,Tim sort 要求 compare 方法实现是可传递的,否则会抛出上述异常,因为我们有一个遗留应用程序我们不想更改代码中的任何内容,因此我们在排序实现内部使用了jvm参数Merge Sortjava.util.Arrays.useLegacyMergeSort=true

于 2021-12-01T12:03:30.973 回答