2

2 つの異なる列/変数で並べ替える必要があるオブジェクトに対して、Java で同等のインターフェイスを実装しようとしています。複数のアプローチを試しましたが、これが今のところ最高です。

public int compareTo(Object o) {
    Match m = (Match)o;
    int diff = m.matches - matches;
    if (diff == 0) {
        if (distance > m.distance) {
            return 1;
        } else if (distance < m.distance) {
            return -1;
        } else {
            return 0;
        }
    } else {
        return diff;
    }
}

しかし、それでも失敗します

java.lang.IllegalArgumentException: Comparison method violates its general contract!

私が間違っていることはありますか?

補足 1: o が null または不適切なクラスの場合、NPEs/ClassCastExceptions が予想されます。これはここでは問題ではありません。

補足 2: JDK 1.7 でのソート アルゴリズムの変更については知っていますが、ここで契約に違反している箇所がわかりません。したがって、例外をオフにすることは間違った解決策のようです。

4

2 に答える 2

5

あなたは double だと言っているのでdistance、ここで説明したのと同じ問題を抱えている可能性があります。

Java エラー:「比較メソッドが一般規約に違反しています!」

多分:

public int compareTo(Object o) {
    Match m = (Match)o;
    int diff = m.matches - matches;
    if (diff == 0) {
        return Double.compare(distance, m.distance);
    } else {
        return diff;
    }
}

ただし、理想的には、以下に述べるように、組み込みの比較メソッドを使用する必要があります。上記のコードは「最小限の変更が必要」の例であり、重要な問題を示しています。

既存の比較方法の使用

また、@ fabian-barney が彼の回答で述べているように、直接の違いをとることを避け、代わりに組み込みの比較方法を利用する必要があります。したがって、次のようなものが必要です。

public int compareTo(Object o) {
    Match m = (Match) o;
    return m.matches == matches ? Double.compare(m.distance, distance) : Integer.compare(m.matches, matches);
}

このようにDouble.compareして、 NaN 値が処理されます。任意の数x(NaN 以外)についてDouble.compare(x, Double.NaN) == -1は true を返します (つまり、NaN は他のどの数よりも大きいと見なされます)。

ここでsを使用==しても問題ないことに注意してください。しかし、本当です。Java の Double.compare(double, double) がこのように実装されている理由を参照してください。良い議論のために。intdoubleDouble.NaN != Double.NaNnew Double(Double.NaN).equals(Double.NaN)

契約違反:

NaN がある場合に元の実装が契約を破る理由の例を確認するには、Java compareTo ドキュメントを参照してください。そこには次のものがあります。

最後に、実装者は、すべての z について、x.compareTo(y)==0 が sgn(x.compareTo(z)) == sgn(y.compareTo(z)) を意味することを確認する必要があります。

ととがあるx = NaNと想像してください。y = 5z = 6

  1. x.compareTo(y) == 0(NaN > 5NaN < 5が false であるため)
  2. x.compareTo(z) == 0(同じ理屈)
  3. y.compareTo(z) == -1(y < z)。

したがって、必要に応じて 2 と 3 (+ sgn) は等しくありません。

于 2012-07-15T21:33:15.293 に答える
2

diffincompareTo(...)メソッドを返さないでください。これは、すべての値に対して有効ではありません。たとえば、 の結果Integer.MAX_VALUE - Integer.MIN_VALUEは負です。

次のように書き換えます。

public int compareTo(Object o) {
    Match m = (Match) o;
    return m.matches == matches ? Double.compare(m.distance, distance) : Integer.compare(m.matches, matches);
}
于 2012-07-15T21:51:27.543 に答える