问题
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.
回答1:
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.
来源:https://stackoverflow.com/questions/33300011/is-there-a-convenience-method-to-create-a-predicate-that-tests-if-a-field-equals