8

私はいくつかのカスタム Comparator を書いています。昇順または降順のどちらでソートしているかに関係なく、null アイテムをリストの一番下にプッシュしたいと思います。これにアプローチするための良い戦略またはパターンは何ですか?

オフハンド:

  • 可能な場合はコードを共有して、個別の昇順および降順のコンパレータを作成するだけです
  • NPE をスローするか、明示的に呼び出すことにより、null 処理を別のクラスに委譲します。
  • 昇順フラグを含め、その中に条件付きロジックを入れて、null をナビゲートします。
  • null 処理クラスで通常のコンパレータをラップする

他の戦略はありますか?さまざまなアプローチの経験や、さまざまな戦略の落とし穴について聞きたいです。

4

5 に答える 5

12

Jon Skeet に同意します (とても簡単です :)。私は非常に単純なデコレータを実装しようとしました:

class NullComparators {

    static <T> Comparator<T> atEnd(final Comparator<T> comparator) {
        return new Comparator<T>() {

            public int compare(T o1, T o2) {
                if (o1 == null && o2 == null) {
                    return 0;
                }

                if (o1 == null) {
                    return 1;
                }

                if (o2 == null) {
                    return -1;
                }

                return comparator.compare(o1, o2);
            }
        };
    }

    static <T> Comparator<T> atBeginning(final Comparator<T> comparator) {
        return Collections.reverseOrder(atEnd(comparator));
    }
}

コンパレータが与えられた場合:

Comparator<String> wrapMe = new Comparator<String>() {
      public int compare(String o1, String o2) {
          return o1.compareTo(o2);
      }
};

そしていくつかのテストデータ:

List<String> strings = Arrays.asList(null, "aaa", null, "bbb", "ccc", null);

最後にnullでソートできます:

Collections.sort(strings, NullComparators.atEnd(wrapMe));
[aaa、bbb、ccc、null、null、null]

または最初に:

Collections.sort(strings, NullComparators.atBeginning(wrapMe));
[ヌル、ヌル、ヌル、ccc、bbb、aaa]
于 2009-08-11T18:28:22.113 に答える
6

最後のオプションは私にとって非常に魅力的です。コンパレーターは、連鎖するのに非常に優れています。ReverseComparator特に、 aだけでなくa も書きたいと思うかもしれませんNullWrappingComparator


編集:これを自分で書く必要はありません。Google Collections LibraryのOrderingクラスを見ると、これと他のあらゆる種類のグッズが見つかります :)


編集:私が何を意味するのかを示すために、より詳細に説明しReverseComparatorます...

警告の一言 - a の実装ではReverseComparator、結果を否定するのではなく、引数の順序を逆にしてくださいInteger.MIN_VALUE

したがって、この実装は間違っています (originalコンパレーターが逆であると仮定します):

public int compare(T x, T y)
{
    return -original.compare(x, y);
}

しかし、これは正しいです:

public int compare(T x, T y)
{
    return original.compare(y, x);
}

その理由は、常に比較を逆にしたいからですが、 をoriginal.compare(x, y)返す場合int.MIN_VALUE、悪い比較子も を返しint.MIN_VALUEます。これは正しくありません。これは、 という面白い性質によるものですint.MIN_VALUE == -int.MIN_VALUE

于 2009-08-11T17:56:53.957 に答える
6

dfaの回答をフォローアップします-私が望むのは、null以外の順序に影響を与えずにnullを最後にソートすることです。だから私はこれに沿ってもっと何かが欲しい:

public class NullComparatorsTest extends TestCase {
    Comparator<String>  forward = new Comparator<String>() {
                                    public int compare(String a, String b) {
                                        return a.compareTo(b);
                                    }
                                };

    public void testIt() throws Exception {
        List<String> strings = Arrays.asList(null, "aaa", null, "bbb", "ccc", null);
        Collections.sort(strings, NullComparators.atEnd(forward));
        assertEquals("[aaa, bbb, ccc, null, null, null]", strings.toString());
        Collections.sort(strings, NullComparators.atBeginning(forward));
        assertEquals("[null, null, null, aaa, bbb, ccc]", strings.toString());
    }
}

public class NullComparators {
    public static <T> Comparator<T> atEnd(final Comparator<T> comparator) {
        return new Comparator<T>() {
            public int compare(T a, T b) {
                if (a == null && b == null)
                    return 0;
                if (a == null)
                    return 1;
                if (b == null)
                    return -1;
                return comparator.compare(a, b);
            }
        };
    }

    public static <T> Comparator<T> atBeginning(final Comparator<T> comparator) {
        return new Comparator<T>() {
            public int compare(T a, T b) {
                if (a == null && b == null)
                    return 0;
                if (a == null)
                    return -1;
                if (b == null)
                    return 1;
                return comparator.compare(a, b);
            }
        };
    }
}

ただし、dfa の功績は完全に認められています。

于 2009-08-11T18:56:00.123 に答える
5

Java 8 では、静的メソッドComparator.nullsLastComparator.nullsFirst静的メソッドを使用して、より null に適したコンパレータを使用できます。Fruit次のようなクラスがあるとします。

public class Fruit {
    private final String name;
    private final Integer size;

    // Constructor and Getters
}

たくさんの果物をサイズで並べ替え、最後に s を付けたい場合null:

List<Fruit> fruits = asList(null, new Fruit("Orange", 25), new Fruit("Kiwi", 5));

あなたは簡単に書くことができます:

Collections.sort(fruits, Comparator.nullsLast(Comparator.comparingInt(Fruit::getSize)));

結果は次のようになります。

[Fruit{name='Kiwi', size=5}, Fruit{name='Orange', size=25}, null]
于 2016-08-08T20:09:31.027 に答える
2

NullComparatorcommons-collections からいつでも使用できます。Google Collections よりも長い歴史があります。

于 2009-08-12T01:31:13.000 に答える