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の既存のメソッドを再利用したいと思います。
そのような組み込みファクトリメソッドはありません。これは、 JFC内のPredicate
のすべての使用法 を調べて、「述語を返す…のメソッド」を探すことで簡単に確認できます。 Predicate
自体のメソッドの他に、Predicate
を返す Pattern.asPredicate()
のみがあります。
このようなファクトリメソッドを実装する前に、それが本当に価値があるかどうかを自問する必要があります。 .filter(a -> Objects.equals(a.getField(), someValue))
のラムダ式が複雑に見えるのは、Objects.equals
の使用です。これは、少なくとも1つの引数についてnull
であるかどうかを予測できる場合は必要ありません。ここでは、someValue
がnull
になることはないため、式を簡略化できます。
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
も同様であることに注意してください。