有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我经常发现自己需要过滤一个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 <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) 个答案

  1. # 1 楼答案

    没有这样的内置工厂方法,您可以通过查看all usages of ^{} within the JFC和“返回谓词中的方法”来轻松检查它。除了^{}本身中的方法之外,只有^{}返回Predicate

    在你打算实施这样一种工厂方法之前,你应该问问自己这是否真的值得。使.filter(a -> Objects.equals(a.getField(), someValue))中的lambda表达式看起来复杂的是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));
    }
    

    这将排除测试常量是否为null的因素,以简化将在每个测试中执行的操作。所以它仍然不需要Objects.equals。注意Predicate.isEqual也有类似的作用