是否有一种方便的方法来创建一个 Predicate 来测试一个字段是否等于给定值? [英] Is there a convenience method to create a Predicate that tests if a field equals a given value?

查看:22
本文介绍了是否有一种方便的方法来创建一个 Predicate 来测试一个字段是否等于给定值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I often find myself in the need to filter a Stream or to use a predicate that checks if a given field has a given value.

比如说我有这个 POJO:

Say for example I have this POJO:

public class A {
    private Integer field;

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

    public Integer getField() {
        return field;
    }
}

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

And I want to filter a Stream of objects based on the value of the 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 但它不符合需要.

Would there be a convenience method to generate the predicate for the filter method? I noticed there is Predicate.isEqual but it does not fit the need.

我可以很容易地写一个这样的:

I could quite easily write one like this:

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 中的现有方法.

but I'd prefer to reuse an existing method from the JDK if possible.

推荐答案

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

There is no such builtin factory method, which you can easily check by looking at all usages of Predicate within the JFC and look for "Methods in … that return Predicate". Besides the methods within Predicate itself, there is only Pattern.asPredicate() which returns a Predicate.

在你打算实现这样一个工厂方法之前,你应该问问自己是否真的值得.是什么让 .filter(a -> Objects.equals(a.getField(), someValue)) 中的 lambda 表达式看起来很复杂,是使用了 Objects.equals当您可以预测至少一个参数是否为 null 时,这是不必要的.由于这里 someValue 永远不是 null,您可以简化表达式:

Before you’re going to implement such a factory method, you should ask yourself whether it’s really worth it. What makes your lambda expression in .filter(a -> Objects.equals(a.getField(), someValue)) look complicated, is the use of Objects.equals which is not necessary when you can predict for at least one argument whether it is null. Since here, someValue is never null, you can simplify the expression:

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()))
    …

如果您仍然想实现工厂方法并通过创造性地使用已有的方法来赢得价格,您可以使用:

If you still want to implement the factory method and win a price for creatively using what is already there, you can use:

public static <T,R> Predicate<T> isEqual(Function<? super T, ? extends R> f, R value) {
    return f.andThen(Predicate.isEqual(value)::test)::apply;
}

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

However, for production code, I’d rather recommend an implementation like this:

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 也有类似的作用.

This factors out the test whether the constant is null to simplify the operation that will be performed in each test. So it still doesn’t need Objects.equals. Note that Predicate.isEqual does similar.

这篇关于是否有一种方便的方法来创建一个 Predicate 来测试一个字段是否等于给定值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆