一尘不染

如何将多个谓词应用于java.util.Stream?

java

如何将多个谓词应用于一个java.util.Stream's filter()方法?

这就是我现在要做的,但是我真的不喜欢它。我有一个Collection东西,我需要根据Collection过滤器(谓词)减少东西的数量:

Collection<Thing> things = someGenerator.someMethod();
List<Thing> filtered = things.parallelStream().filter(p -> {
   for (Filter f : filtersCollection) {
      if (f.test(p))
        return true;
   }
   return false;
}).collect(Collectors.toList());

我知道,如果我预先知道过滤器的数量,则可以执行以下操作:

List<Thing> filtered = things.parallelStream().filter(filter1).or(filter2).or(filter3)).collect(Collectors.toList());

但是如何在不混合编程样式的情况下应用未知数量的谓词?众所周知,它看起来有点丑陋。


阅读 207

收藏
2020-09-09

共1个答案

一尘不染

我假设您Filter的类型不同于java.util.function.Predicate,这意味着需要对其进行调整。一种可行的方法如下:

things.stream().filter(t -> filtersCollection.stream().anyMatch(f -> f.test(t)));

这会为每个谓词评估重新创建过滤器流带来轻微的性能损失。为避免这种情况,您可以将每个过滤器包装到中Predicate并组成它们:

things.stream().filter(filtersCollection.stream().<Predicate>map(f -> f::test)
                       .reduce(Predicate::or).orElse(t->false));

但是,由于现在每个过滤器都落后于自己Predicate,引入了更高级别的间接访问,因此尚不清楚哪种方法具有更好的整体性能。

没有适应性的关注(如果您Filter碰巧是Predicate),问题陈述将变得更加简单,第二种方法显然会胜出:

things.stream().filter(
   filtersCollection.stream().reduce(Predicate::or).orElse(t->true)
);
2020-09-09