1

そのIDが選択されたアイテムのIDと等しい場合、アイテムを配列の先頭に移動する必要があるアイテムの配列をソートしようとしています(これも配列に属しています)。残りの要素の並べ替え順序は、特定の場所からの距離です。

次のように実装されたカスタム コンパレータで恐ろしいjava.lang.IllegalArgumentException: Comparison method violates its general contract!例外が発生しています。

Location location = ...; // may be null
Item selectedItem = ...; // may be null or an element of the array to be sorted

private final Comparator<Item> comparator = new Comparator<Item>() {
    @Override
    public int compare(Item p1, Item p2) {
        // if p1 is the currently selected item, bring p1 to the top
        // if p2 is the currently selected item, bring p2 to the top
        // else sort p1 and p2 by their distance from location
        if (selectedItem != null) {
            if (selectedItem.getId() == p1.getId()) { //id's are int and unique in the array
                return -1;
            } else if (selectedItem.getId() == p2.getId()) {
                return 1;
            }
        }

        if (location != null) { //location is an Android Location class instance
            Float distance1 = location.distanceTo(p1.getLocation());
            Float distance2 = location.distanceTo(p2.getLocation());
            return distance1.compareTo(distance2);
        } else {
            return 0;
        }
    }
};

問題を再現するための正確なシーケンスはありませんが、これまでのエラーの観察はすべて、selectedItemlocationが null でない場合に発生します (両方とも null の可能性があります)。

ヒントはありますか?

ありがとう

4

2 に答える 2

1

あなたの問題は、に等しいselectedItem場合、比較される2つの要素が等しいときに0を返さないという事実にあると思います。このように、と比較xするyと、sayxの方が大きくなりますが、say と比較yすると、より大きくなります (とが両方とも に等しいと仮定します)。これはできません。xyxyselectedItem

if (p1.getId() == p2.getId()) return 0;
于 2013-05-15T20:37:12.870 に答える
0

この質問への回答にヒントがあると思います: https://stackoverflow.com/a/8327575/338479

コンパレータにはルール (「コントラクト」) があります。1 つは、オブジェクトが常にそれ自体と等しい ( compare()0 を返す) ことです。もう 1 つは、A>B かつ B>C の場合、A>C です。もう 1 つは、B>A は A>B とは逆の結果を返すことです。

あなたのコンパレーターでこれらのルールに対する明らかな違反は見られませんが、あなたの他のコードの内部動作については知りません。あなたのdistanceTo()方法がこの契約の規則に違反している可能性がある場合はありますか?

並べ替えの途中で場所またはselectedItemが変更される可能性はありますか?

于 2013-05-15T22:00:02.123 に答える