“比较方法违反了其总合同!”

问题

有人可以用简单的语言解释我,为什么这个代码会抛出异常,"比较方法违反了它的一般合同!",我该如何修复它?

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

#1 热门回答(214 赞)

你的比较器不可传递。
LetAB的父代,而BC的父代。自A > BB > C,那么一定是A > C的情况。但是,如果在3b585291和C上调用比较器,它将返回零,即A == C。这违反了合同,因此抛出异常。

图书馆检测到这个并让你知道,而不是表现得不正常,这是相当不错的。

满足compareParents()中的传递性要求的一种方法是遍历getParent()链,而不是仅仅查看直接祖先。


#2 热门回答(32 赞)

只是因为这是我在谷歌搜索这个错误时得到的,我的问题是我有

if (value < other.value)
  return -1;
else if (value >= other.value)
  return 1;
else
  return 0;

thevalue >= other.value应该(显然)实际上是value > other.value,你实际上可以用相同的对象返回0。


#3 热门回答(19 赞)

违反合同通常意味着比较器在比较对象时没有提供正确或一致的值。例如,你可能希望执行字符串比较并强制将空字符串排序到最后:

if ( one.length() == 0 ) {
    return 1;                   // empty string sorts last
}
if ( two.length() == 0 ) {
    return -1;                  // empty string sorts last                  
}
return one.compareToIgnoreCase( two );

但是这忽略了一个和两个都是空的情况 - 在这种情况下,返回错误的值(1而不是0来显示匹配),并且比较器报告为违规。应该写成:

if ( one.length() == 0 ) {
    if ( two.length() == 0 ) {
        return 0;               // BOth empty - so indicate
    }
    return 1;                   // empty string sorts last
}
if ( two.length() == 0 ) {
    return -1;                  // empty string sorts last                  
}
return one.compareToIgnoreCase( two );