是否有一种方便的方法来创建一个测试字段是否等于给定值的谓词?
我经常发现自己需要过滤Stream
或使用谓词来检查给定字段是否具有给定值。
比方说,我有这个POJO:
public class A { private Integer field; public A(final Integer field) { this.field = field; } public Integer getField() { return field; } }
我想根据field
的值过滤对象Stream
:
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 Predicate isEqual(Function 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
本身的方法之外,只有Pattern.asPredicate()
返回一个Predicate
。
在你要实现这样一种工厂方法之前,你应该问问自己这是否真的值得。 是什么让你的lambda表达式在.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 Predicate isEqual(Function super T, ? extends R> f, R value) { return f.andThen(Predicate.isEqual(value)::test)::apply; }
但是,对于生产代码,我宁愿推荐这样的实现:
public static Predicate 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
类似。