【发布时间】:2019-01-08 14:18:29
【问题描述】:
注意:这个问题不与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 进行不必要的调用,这可能会在扩展时产生一些性能成本。
所以我的问题是:有没有更好的方法来生成包含可选过滤的链式流表达式?
更新:也许我说得不够清楚,但我的问题的重点是找到一个单表达式解决方案。如果我必须使用多个语句(例如,初始化谓词),我还可以使用问题的第一个代码块,它本质上是相同的。
【问题讨论】:
-
needsFilter1或needsFilter2总是保证为真? -
不,这些条件彼此无关,可以是任何情况。此外,我需要执行的过滤操作并不总是两个。我只列出了两个以使帖子更短,但可能更多。我正在寻找一种无论您要执行多少过滤都可以工作的模式。
-
您可以使用
.filter(c->(needsFilter1 && whatever1()),它比您的三元表达式更短且更具可读性,并希望 JIT 能够意识到needsFilter1是一个常量(或不变)表达式并对其进行优化。跨度> -
@KlitosKyriacou 如果你使用
.filter(c->(needsFilter1 && whatever1())并且needsFilter1是false,你最终会得到一个为流的所有元素返回false的谓词。显然,这是错误的,因为 OP 在这种情况下想要跳过过滤。 -
@FedericoPeraltaSchaffner 好收获!我的意思是
.filter(c->(!needsFilter1 || whatever1())。
标签: java lambda java-8 java-stream predicate