将 Java 8 lambda 谓词与逻辑运算符相结合

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41571836/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 05:58:10  来源:igfitidea点击:

Combining Java 8 lambda predicates with logical operators

javalambdajava-8

提问by lexicore

I have a Stream<SomeClass> streamwhereas SomeClasshas boolean methods isFoo()and isBar().

我有一个Stream<SomeClass> streamwhileSomeClass有布尔方法isFoo()isBar().

I'd like to check that all elements in the stream have both isFoo()and isBar()equals to true. I can check this conditions individually via SomeClass:isFooand SomeClass::isBarlambdas.

我想检查流中的所有元素是否都同时具有isFoo()isBar()等于true。我可以通过SomeClass:isFooSomeClass::isBarlambdas单独检查这些条件。

But how would I combine these two lambdas with a logical operator like and/&&?

但是我如何将这两个 lambda 表达式与像and/这样的逻辑运算符结合起来&&

One obvious way is to write an extra lambda:

一种明显的方法是编写一个额外的 lambda:

stream.allMatch(item -> item.isFoo() && item.isBar());

But I'd like to avoid writing an extra lambda.

但我想避免编写额外的 lambda。

Another way is to cast to Predicate<? super SomeClass>:

另一种方法是投射到Predicate<? super SomeClass>

stream.allMatch(((Predicate<? super SomeClass>) SomeClass::isFoo).and(SomeClass::isBar));

Is there a better way - without casts and explicit lambdas?

有没有更好的方法 - 没有强制转换和显式 lambda 表达式?

回答by John Kugelman

If there were a hypothetical Predicate.ofmethod, you could write:

如果有一种假设的Predicate.of方法,你可以写:

stream.allMatch(Predicate.of(SomeClass::isFoo).or(SomeClass::isBar));

It doesn't exist, but you could write it yourself.

它不存在,但您可以自己编写。

public final class Predicates {
    public static <T> Predicate<T> of(Predicate<T> predicate) {
        return predicate;
    }
}

That said, I would personally go with your first option.

也就是说,我个人会选择你的第一个选择。

stream.allMatch(item -> item.isFoo() && item.isBar());

::method references are nice but sometimes you have to write explicit lambdas.

::方法引用很好,但有时您必须编写显式的 lambda。

回答by Eugene

This might not qualify as the answer (please don't up vote it if it does not), but I sort ofhad the same need, to munch together some predicates and I just wrote a small utility for that.

这也许不能算作答案(请如果不这样做不起来投票吧),但我有点有同样的需要,咀嚼一些谓词在一起,我只是写了一个小程序来达到这个。

private static <T> Predicate<T> andPredicates(Predicate<T>... predicates) {
    return Arrays.stream(predicates).reduce(Predicate::and).orElse(x -> true);
}

回答by GeneralBecos

You could filter and only collect the size of the list and compare with the original list :

您可以过滤并仅收集列表的大小并与原始列表进行比较:

long count = list.stream().filter(SomeClass::isFoo).filter(SomeClass::isBar).collect(Collectors.counting());

long count = list.stream().filter(SomeClass::isFoo).filter(SomeClass::isBar).collect(Collectors.counting());

回答by Andrea

You should definitely use the filtermethod of Stream. Filter select the elements of the list that match the given predicate.

您绝对应该使用Stream的过滤器方法。过滤器选择与给定谓词匹配的列表元素。

This line select the elements which are Foo AND Bar at the same time:

这一行同时选择了 Foo AND Bar 的元素:

list.stream().filter(SomeClass::isFoo).filter(SomeClass::isBar)

The output is a Stream, so you should collect the elements in a List to actually use them:

输出是一个 Stream,因此您应该收集 List 中的元素以实际使用它们:

 list.stream().filter(SomeClass::isFoo).filter(SomeClass::isBar).collect(Collectors.toList());


In order to check if all the elements of the stream are both Foo and Bar, you could compare the size of the original list with the size of the filtered stream:

为了检查流的所有元素是否都是 Foo 和 Bar,您可以将原始列表的大小与过滤流的大小进行比较:

public static Boolean isFooBar(List<SomeClass> list) {
    return list.size() == list.stream().filter(SomeClass::isFoo).filter(SomeClass::isBar).count();
}