在Java 7中,比较方法违反了其一般合同。

20

我在编译一些Java 7代码并运行后,遇到了一个"Comparison Method violates its general contract(比较方法违反了其总体契约)"的错误。

我已经阅读了Comparison method violates its general contract! Java 7 only,意识到我的代码中存在问题,在之前的Java版本中被忽略了。但是我无法确定我的代码哪里有问题,而Collections.sort()生成了这个错误。

我的代码如下:

   public Comparator sortBySmoothDays() {
    Comparator c = new Comparator() {
        public int compare(Object arg0, Object arg1) {
            Date date0 = ((PosObject)arg0).getDate();
            Date date1 = ((PosObject)arg1).getDate();

            double d1 = MyUtils.calcSmoothDays(date0, new Date());
            double d2 = MyUtils.calcSmoothDays(date1, new Date());
            if (d1 >= d2) {
                return 1;
            }
            else {
                return -1;
            }   
        }
    };
    return c;
}


Comparator c = ComparatorUtils.getInstance().sortBySmoothDays();
Collections.sort(posList, c);

有人能帮忙吗?谢谢!


JFI:抛出此异常是Java7的新功能。旧行为可以通过一个新的系统属性进行配置:java.util.Arrays.useLegacyMergeSort,请参阅https://dev59.com/eGsz5IYBdhLWcg3wg4Gv#8417446。 - alfonx
3个回答

32

如果值相等,比较器必须返回0。在您当前的实现中,如果它们相等,则返回1。正确比较您的double值的最简单方法是调用Double.compare

double d1 = MyUtils.calcSmoothDays(date0, new Date());
double d2 = MyUtils.calcSmoothDays(date1, new Date());

return Double.compare(d1, d2);

它返回1,而不是-1。 - xehpuk
@Boann 因为3.5年前的我很傻 :). 请随意编辑答案。 - Kevin Crowell

19

使用您的比较器,每个对象与其自身比较时都会返回更大值: compare(x,x) 总是返回 1。

这违反了以下要求

实现者必须确保对于所有的 x 和 y, sgn(compare(x, y)) == -sgn(compare(y, x))。

以上要求意味着 compare(x,x) 必须返回零。

我建议阅读合同并确保您的实现符合它。

特别地,在 date0.equals(date1) 的情况下,比较器可能应该立即返回零,而不进行任何浮点数转换和比较。


更普遍地说,使用这种方法永远不可能使两个对象相等。没有代码路径会产生0(或相等)的结果。 - Ian McLaird

3

问题不在于如果两个对象比较相等,即calcSmoothDays返回相同的值,那么你可能会有这样一种情况:compare(object1,object2) == 1,且compare(object2,object1) == 1?

因此,这意味着object1> object 2和object2> object 1...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接