首页 > 解决方案 > Java 流:对链接使用可选的 filter() 操作

问题描述

注意:这个问题.java.util.Optional

在处理流时,我经常使用这样的逻辑:

 Stream<FooBar> stream = myInitialStream();
 if (needsFilter1) stream = stream.filter(c -> whatever1());
 if (needsFilter2) stream = stream.filter(c -> whatever2());
 ...
 return stream.collect(toList());

我想要实现的是使用链接将上面的代码转换为单个表达式。我发现这更具可读性和直截了当。到目前为止,我发现实现这一目标的唯一方法是:

return myInitialStream()
       .filter(needsFilter1? c->whatever1() : c->true)
       .filter(needsFilter2? c->whatever2() : c->true)
       .collect(toList());

c->true尽管如此,这会对那些琐碎的lamdas进行不必要的调用,这可能会在扩展时产生一些性能成本。

所以我的问题是:有没有更好的方法来生成包含可选过滤的链式流表达式?

更新:也许我说得不够清楚,但我的问题的重点是找到一个单一的表达式解决方案。如果我必须使用多个语句(例如,初始化谓词),我也可以使用我的问题的第一个代码块,它本质上是相同的。

标签: javalambdajava-8java-streampredicate

解决方案


Predicate::and使用返回一个新的谓词根据条件链接谓词。

Predicate<FooBar> predicate = c -> whatever();

if (condition1) { predicate = predicate.and(c -> whatever1()); }
if (condition2) { predicate = predicate.and(c -> whatever2()); }

List<FooBar> dest = list.stream()
    .filter(predicate)
    .collect(Collectors.toList());

在更新请求单个表达式时。无论如何,您都需要一个映射条件的来源到谓词。对于数据结构Map<Supplier<Boolean>, Predicate<Integer>>,其中键是决定是否应使用Supplier值()的条件。Predicate<FooBar>

使用将它们与Predicate<FooBar>链接起来,将映射的条目减少到新的条目,它们的返回(条件有效)。PredicatesPredicate::andSupplier<Boolean>true

具备Map以下条件之一:

Map<Supplier<Boolean>, Predicate<FooBar>> map = new HashMap<>();
map.put(() -> needsFilter1, c -> whatever1());
map.put(() -> needsFilter2, c -> whatever2());
...

这是一个单一的Stream声明:

List<Integer> dest = list
        .stream()
        .filter(map.entrySet()                            // filter with a predicate ...
                .stream()
                .filter(e -> e.getKey().get())            // .. where a condition is 'true'
                .map(Entry::getValue)                     // .. get Predicates
                .reduce(i -> true, (l, r) -> l.and(r)))   // .. reduce them using AND
        .collect(Collectors.toList());               

推荐阅读