谁能简单地解释一下,为什么这段代码抛出一个异常,“比较方法违反了它的一般契约!”,以及我该如何修复它?

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

当前回答

只是因为这是我得到的当我谷歌这个错误,我的问题是我有

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

>= other。Value(显然)实际上应该是Value > other。值,这样你就可以用相等的对象返回0。

其他回答

在我的例子中,它是无限排序。 也就是说,首先这条线根据条件向上移动,然后这条线向下移动到相同的位置。 我在最后添加了一个条件,明确地建立了行序。

即使你的compareTo在理论上具有可传递性,有时细微的bug会把事情搞糟……如浮点运算错误。这件事发生在我身上。这是我的代码:

public int compareTo(tfidfContainer compareTfidf) {
    //descending order
    if (this.tfidf > compareTfidf.tfidf)
        return -1;
    else if (this.tfidf < compareTfidf.tfidf)
        return 1;
    else
        return 0;

}   

传递属性显然持有,但由于某种原因,我得到了IllegalArgumentException。事实证明,由于浮点运算中的微小错误,舍入错误导致传递属性在不应该发生的地方中断!所以我重写了代码,考虑到真正微小的差异0,它工作:

public int compareTo(tfidfContainer compareTfidf) {
    //descending order
    if ((this.tfidf - compareTfidf.tfidf) < .000000001)
        return 0;
    if (this.tfidf > compareTfidf.tfidf)
        return -1;
    else if (this.tfidf < compareTfidf.tfidf)
        return 1;
    return 0;
}   

如果compareParents(s1, s2) == -1,则期望compareParents(s2, s1) == 1。对于你的代码,这并不总是正确的。

具体来说,如果s1. getparent () == s2 && s2. getparent () == s1。 这只是可能出现的问题之一。

在我们的例子中,我们得到这个错误是因为我们不小心颠倒了s1和s2比较的顺序。所以要小心。它显然比下面的要复杂得多,但这是一个例子:

s1 == s2   
    return 0;
s2 > s1 
    return 1;
s1 < s2 
    return -1;

从严格意义上讲,Java并不检查一致性,只是在遇到严重问题时才通知您。此外,它也没有从错误中提供太多信息。

我对在我的分类器中发生的事情感到困惑,并做了一个严格的consistencyChecker,也许这将帮助你:

/**
 * @param dailyReports
 * @param comparator
 */
public static <T> void checkConsitency(final List<T> dailyReports, final Comparator<T> comparator) {
  final Map<T, List<T>> objectMapSmallerOnes = new HashMap<T, List<T>>();

  iterateDistinctPairs(dailyReports.iterator(), new IPairIteratorCallback<T>() {
    /**
     * @param o1
     * @param o2
     */
    @Override
    public void pair(T o1, T o2) {
      final int diff = comparator.compare(o1, o2);
      if (diff < Compare.EQUAL) {
        checkConsistency(objectMapSmallerOnes, o1, o2);
        getListSafely(objectMapSmallerOnes, o2).add(o1);
      } else if (Compare.EQUAL < diff) {
        checkConsistency(objectMapSmallerOnes, o2, o1);
        getListSafely(objectMapSmallerOnes, o1).add(o2);
      } else {
        throw new IllegalStateException("Equals not expected?");
      }
    }
  });
}

/**
 * @param objectMapSmallerOnes
 * @param o1
 * @param o2
 */
static <T> void checkConsistency(final Map<T, List<T>> objectMapSmallerOnes, T o1, T o2) {
  final List<T> smallerThan = objectMapSmallerOnes.get(o1);

  if (smallerThan != null) {
    for (final T o : smallerThan) {
      if (o == o2) {
        throw new IllegalStateException(o2 + "  cannot be smaller than " + o1 + " if it's supposed to be vice versa.");
      }
      checkConsistency(objectMapSmallerOnes, o, o2);
    }
  }
}

/**
 * @param keyMapValues 
 * @param key 
 * @param <Key> 
 * @param <Value> 
 * @return List<Value>
 */ 
public static <Key, Value> List<Value> getListSafely(Map<Key, List<Value>> keyMapValues, Key key) {
  List<Value> values = keyMapValues.get(key);

  if (values == null) {
    keyMapValues.put(key, values = new LinkedList<Value>());
  }

  return values;
}

/**
 * @author Oku
 *
 * @param <T>
 */
public interface IPairIteratorCallback<T> {
  /**
   * @param o1
   * @param o2
   */
  void pair(T o1, T o2);
}

/**
 * 
 * Iterates through each distinct unordered pair formed by the elements of a given iterator
 *
 * @param it
 * @param callback
 */
public static <T> void iterateDistinctPairs(final Iterator<T> it, IPairIteratorCallback<T> callback) {
  List<T> list = Convert.toMinimumArrayList(new Iterable<T>() {

    @Override
    public Iterator<T> iterator() {
      return it;
    }

  });

  for (int outerIndex = 0; outerIndex < list.size() - 1; outerIndex++) {
    for (int innerIndex = outerIndex + 1; innerIndex < list.size(); innerIndex++) {
      callback.pair(list.get(outerIndex), list.get(innerIndex));
    }
  }
}