web-dev-qa-db-ja.com

java.lang.IllegalArgumentException:比較メソッドが一般契約に違反しています

こんにちは、私のコンパレータの比較方法です。何が悪いのか分かりません。私はスタックオーバーフローに関する他の同様のタイトルの質問と回答を調べましたが、私のメソッドの何が間違っているのかわかりませんが、Java.lang.IllegalArgumentExceptionを取得し続けています:比較メソッドはその一般的な契約に違反しています!

どんな助けも大歓迎です

public int compare(Node o1, Node o2)
{
    HashMap<Integer,Integer> childMap = orderMap.get(parentID);
    if(childMap != null && childMap.containsKey(o1.getID()) && 
                           childMap.containsKey(o2.getID()))
    {
        int order1 = childMap.get(o1.getID());
        int order2 = childMap.get(o2.getID());

        if(order1<order2) 
            return -1;
        else if(order1>order2) 
            return 1;
        else 
            return 0;
    }
    else
        return 0;
}

私が得ている例外を追加する

Java.lang.IllegalArgumentException: Comparison method violates its general contract!
at Java.util.TimSort.mergeLo(TimSort.Java:747)
at Java.util.TimSort.mergeAt(TimSort.Java:483)
at Java.util.TimSort.mergeCollapse(TimSort.Java:410)
at Java.util.TimSort.sort(TimSort.Java:214)
at Java.util.TimSort.sort(TimSort.Java:173)
at Java.util.Arrays.sort(Arrays.Java:659)
at Java.util.Collections.sort(Collections.Java:217)
45
Chandu

compare()メソッドはnottransitiveです。 A == BおよびB == Cの場合、ACと等しくなければなりません。

次に、このケースを検討します。

AB、およびCの場合、containsKey()メソッドがこれらの結果を返すと仮定します。

  • childMap.containsKey(A.getID())trueを返します
  • childMap.containsKey(B.getID())falseを返します
  • childMap.containsKey(C.getID())trueを返します

また、A.getId()!= B.getId()の注文を検討してください。

そう、

  1. AB0を返します。外側のif条件はfalse => A == Bになるためです
  2. BC0を返します。外側のif条件はfalse => B == Cになるためです

ただし、AおよびCは、ifブロック内のテストに基づいて、-1または1を返す可能性があります。したがって、A != C。これは、推移性の原則に違反しています。

elseブロック内に何らかの条件を追加して、ifブロックで行うのと同様のチェックを実行する必要があると思います。

58
Rohit Jain

問題はデフォルトの場合だと思います。 IDが'a''b'、および'c'であるノードA、B、およびCのセットを考えます。さらに、相対的な注文情報を含むchildMapの内容が次のとおりであることを考慮してください。

{ 'a' => 1, 'c' => 3 }

compareメソッドをAとBで実行すると、0が返され、AとBが同等であることを示します。さらに、BとCを比較しても、0を返します。ただし、AとCを比較すると、-1を返し、Aが小さいことを示します。これは Comparator契約 の推移性プロパティに違反します。

実装者は、関係が推移的であることも確認する必要があります。((compare(x, y)>0) && (compare(y, z)>0))compare(x, z)>0を意味します。

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

「順序が割り当てられていないアイテム」は、値が「漠然と中間にある」として扱うことはできません。ソートアルゴリズムはそれらをどこに置くかわからないからです。このアプローチを維持したい場合、値がマップに存在しない場合は、順序値となる固定値を割り当てる必要があります。 0またはMIN_INTのようなものが妥当な選択です(ただし、compare!については、Javadocですべての選択を文書化する必要があります)。

4
chrylis