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

我经常发现自己需要过滤一个或使用一个谓词来检查给定字段是否具有给定值。Stream

例如,假设我有这个POJO:

public class A {
    private Integer field;

    public A(final Integer field) {
        this.field = field;
    }

    public Integer getField() {
        return field;
    }
}

我想根据的值过滤一个对象:Streamfield

    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))
            ...

是否有方便的方法来生成该方法的谓词?我注意到有,但它不符合需求。filterPredicate.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中的现有方法。


答案 1

没有这样的内置工厂方法,您可以通过查看JFC中谓词的所有用法并查找“方法...返回谓词”。除了谓词本身中的方法之外,只有 Pattern.asPredicate() 返回 .Predicate

在你要实现这样的工厂方法之前,你应该问问自己它是否真的值得。使 lambda 表达式看起来很复杂的是,当您可以预测至少一个参数是否为 .由于这里, 从不 ,你可以简化表达式:.filter(a -> Objects.equals(a.getField(), someValue))Objects.equalsnullsomeValuenull

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));
}

这考虑了测试常量是否是为了简化将在每个测试中执行的操作。因此,它仍然不需要.请注意,这样做类似。nullObjects.equalsPredicate.isEqual


答案 2