我经常发现自己需要过滤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中的现有方法。
没有这样的内置工厂方法,可以通过查看all usages of Predicate
within the JFC并查找“ ...中返回谓词的方法”来轻松检查。除了Predicate
本身中的方法外,只有Predicate
返回一个Predicate
。
在实施这种工厂方法之前,应先问问自己是否真的值得。使Pattern.asPredicate()
中的lambda表达式看起来很复杂的原因是Pattern.asPredicate()
的使用,当您可以预测至少一个参数是否为Predicate
时,则不必使用。由于这里.filter(a -> Objects.equals(a.getField(), someValue))
从不Objects.equals
,因此可以简化表达式:
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));
}
的作用类似。
在Java 8及更高版本中,您现在可以使用null
。