I often find myself in the need to filter a Stream
or to use a predicate that checks if a given field has a given value.
Say for example I have this POJO:
public class A {
private Integer field;
public A(final Integer field) {
this.field = field;
}
public Integer getField() {
return field;
}
}
And I want to filter a Stream
of objects based on the value of the 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))
...
Would there be a convenience method to generate the predicate for the filter
method? I noticed there is Predicate.isEqual
but it does not fit the need.
I could quite easily write one like this:
public static <T,R> Predicate<T> isEqual(Function<? super T, ? extends R> f, R value) {
return v -> Objects.equals(value, f.apply(v));
}
and use it as:
Stream.of(new A(42), new A(1729), new A(42), new A(87539319), new A(null))
.filter(isEqual(A::getField, someValue))
...
but I'd prefer to reuse an existing method from the JDK if possible.
There is no such builtin factory method, which you can easily check by looking at all usages of Predicate
within the JFC and look for “Methods in … that return Predicate”. Besides the methods within Predicate
itself, there is only Pattern.asPredicate()
which returns a Predicate
.
Before you’re going to implement such a factory method, you should ask yourself whether it’s really worth it. What makes your lambda expression in .filter(a -> Objects.equals(a.getField(), someValue))
look complicated, is the use of Objects.equals
which is not necessary when you can predict for at least one argument whether it is null
. Since here, someValue
is never null
, you can simplify the expression:
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()))
…
If you still want to implement the factory method and win a price for creatively using what is already there, you can use:
public static <T,R> Predicate<T> isEqual(Function<? super T, ? extends R> f, R value) {
return f.andThen(Predicate.isEqual(value)::test)::apply;
}
However, for production code, I’d rather recommend an implementation like this:
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));
}
This factors out the test whether the constant is null
to simplify the operation that will be performed in each test. So it still doesn’t need Objects.equals
. Note that Predicate.isEqual
does similar.