web-dev-qa-db-ja.com

フィールドが指定された値に等しいかどうかをテストする述語を作成する便利な方法はありますか?

Streamをフィルタリングしたり、特定のフィールドに特定の値があるかどうかをチェックする述語を使用したりする必要があることに気付くことがよくあります。

たとえば、私はこのPOJOを持っているとしましょう。

public class A {
    private Integer field;

    public A(final Integer field) {
        this.field = field;
    }

    public Integer getField() {
        return field;
    }
}

そして、Streamの値に基づいてオブジェクトのfieldをフィルタリングしたいと思います。

    final Integer someValue = 42;
    Stream.of(new A(42), new A(1729), new A(42), new A(87539319), new A(null))
            .filter(a -> Objects.equals(a.getField(), someValue))
            ...

filterメソッドの述語を生成するための便利なメソッドはありますか? Predicate.isEqualがあることに気づきましたが、ニーズに合いません。

私はこのようなものを非常に簡単に書くことができました:

public static <T,R> Predicate<T> isEqual(Function<? super T, ? extends R> f, R value) {
    return v -> Objects.equals(value, f.apply(v));
}

そしてそれを次のように使用します:

    Stream.of(new A(42), new A(1729), new A(42), new A(87539319), new A(null))
            .filter(isEqual(A::getField, someValue))
            ...

ただし、可能であれば、JDKの既存のメソッドを再利用したいと思います。

15
Didier L

そのような組み込みファクトリメソッドはありません。これは、 JFC内のPredicateのすべての使用法 を調べて、「述語を返す…のメソッド」を探すことで簡単に確認できます。 Predicate 自体のメソッドの他に、Predicateを返す Pattern.asPredicate() のみがあります。

このようなファクトリメソッドを実装する前に、それが本当に価値があるかどうかを自問する必要があります。 .filter(a -> Objects.equals(a.getField(), someValue))のラムダ式が複雑に見えるのは、Objects.equalsの使用です。これは、少なくとも1つの引数についてnullであるかどうかを予測できる場合は必要ありません。ここでは、someValuenullになることはないため、式を簡略化できます。

final Integer someValue = 42;
Stream.of(new A(42), new A(1729), new A(42), new A(87539319), new A(null))
    .filter(a -> someValue.equals(a.getField()))
    …

それでもファクトリメソッドを実装し、すでに存在するものを創造的に使用するための価格を獲得したい場合は、次を使用できます。

public static <T,R> Predicate<T> isEqual(Function<? super T, ? extends R> f, R value) {
    return f.andThen(Predicate.isEqual(value)::test)::apply;
}

ただし、本番コードの場合は、次のような実装をお勧めします。

public static <T,R> Predicate<T> isEqual(Function<? super T, ? extends R> f, R value) {
    return value==null? t -> f.apply(t)==null: t -> value.equals(f.apply(t));
}

これにより、定数がnullであるかどうかのテストが除外され、各テストで実行される操作が簡略化されます。したがって、まだObjects.equalsは必要ありません。 Predicate.isEqualも同様であることに注意してください。

11
Holger