比较方法违反了它的通用契约!

221

能否简单地解释一下为什么这段代码会抛出异常“Comparison method violates its general contract!”,以及如何修复它?

private int compareParents(Foo s1, Foo s2) {
    if (s1.getParent() == s2) return -1;
    if (s2.getParent() == s1) return 1;
    return 0;
}

1
异常的名称和类是什么?它是IllegalArgumentException吗?如果我猜的话,我会认为你应该执行s1.getParent().equals(s2)而不是s1.getParent() == s2 - Freiheit
还有被抛出的异常。 - Matthew Farwell
2
我对Java或Java比较API并不了解,但这种比较方法似乎是完全错误的。假设s1s2的父节点,而s2不是s1的父节点。那么compareParents(s1, s2)等于0,但compareParents(s2, s1)却等于1。这没有意义。(此外,就像下面aix提到的那样,它也不具有传递性。) - mqp
4
该错误似乎只由特定库http://cr.openjdk.java.net/~martin/webrevs/openjdk7/timsort/src/share/classes/java/util/TimSort.java.html产生。 - Peter Lawrey
在Java中,您可以使用equals(返回布尔值)或compareTo(返回-1、0或+1)。覆盖Foo类中的这些函数后,您可以检查s1.getParent().equals(s2) ... - Mualig
异常是否抛出取决于所使用的JRE版本。Java6将允许此操作,而Java7和8将抛出错误。 - THelper
14个回答

1
在我的情况下,这是一种无限排序。也就是说,首先根据条件线向上移动,然后同样的线向下移动到相同的位置。最后我在末尾添加了一个条件,明确地确定了行的顺序。

0

您不能像这样比较对象数据:s1.getParent() == s2 - 这将比较对象引用。您应该为Foo类覆盖equals函数,然后像这样进行比较s1.getParent().equals(s2)


不,实际上我认为OP正在尝试对某种列表进行排序,并希望实际比较引用。 - Edward Falk

0
所以,这种情况发生的主要原因是比较或compareTo方法没有遵循比较的基本契约,即传递性。
`If A>B And B>C then A has to be greater than A has to greater than C`

请不要直接跳到使用。
` -Djava.util.Arrays.useLegacyMergeSort=true `

它会导致你的排序逻辑出现错误。
`   
    Foo s1 = new Foo();
    Foo s2 = new Foo();
    Foo s3 = new Foo();

    s1.setParent(s2);
    s2.setParent(s3);
    s3.setParent(s1);

    compareParents(s1, s2); // returns -1
    compareParents(s2, s3); // returns 1
    compareParents(s1, s3); // returns 1
`

在这些情况下,你的compareParents方法将破坏传递性。

-1

我遇到了同样的问题,但我已经解决了它。

//This this your code

private int compareParents(Foo s1, Foo s2) {
    if (s1.getParent() == s2) return -1;
    if (s2.getParent() == s1) return 1;
    return 0;
}

违规操作是将不同的事物进行比较。

//acceptable
compare between s1.getParent() and s2.getParent()

//acceptable
compare between s1 and s2

//NOT acceptable
compare between s1 and s2.getParent()

//NOT acceptable
compare between s1.getParent() and s2

在我的代码中,我想按它们的坐标对地址进行排序。在比较器中,我错误地比较了 X 和 Y,而不是 X 和 X。
//My code:
    private void sortBasedOnX(){
        //addresses is a list of addresses where each address has X and Y
        addresses.sort((o1, o2) -> {

            String a = o1.getAddress().getX(); 
            String b = o2.getAddress().getY(); //<-- this is supposed to be getX

            return Integer.parseInt(a)-Integer.parseInt(b);
        });
    }

//acceptable
compare between o1.getAddress().getX() and o1.getAddress().getX()

//acceptable
compare between o1.getAddress().getY() and o1.getAddress().getY()

//NOT acceptable
compare between o1.getAddress().getX() and o1.getAddress().getY()

//NOT acceptable
compare between o1.getAddress().getX() and o1.getAddress()

//NOT acceptable
compare between o1.getAddress().getX() and o1

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