是否有一种方便的方法来创建一个测试字段是否等于给定值的谓词?

我经常发现自己需要过滤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 f, R value) { return f.andThen(Predicate.isEqual(value)::test)::apply; } 

但是,对于生产代码,我宁愿推荐这样的实现:

 public static  Predicate isEqual(Function f, R value) { return value==null? t -> f.apply(t)==null: t -> value.equals(f.apply(t)); } 

这会导致测试该常量是否为null以简化将在每个测试中执行的操作。 所以它仍然不需要Objects.equals 。 请注意, Predicate.isEqual类似。