地图是否在筛选findAny之前应用于整个列表?

huangapple go评论76阅读模式
英文:

Is map applied on all the list before filter findAny?

问题

我想筛选一个列表中具有非空属性的元素,并返回该属性:

list.stream.map(a -> StringUtils.trimToEmpty(a.getProp())).filter(p -> StringUtils.isNotEmpty(p)).findAny().orElse("");

上面的代码首先是否映射了所有元素?出于效率原因,我想逐个处理元素。

英文:

I want to filter a list for elements having a non null property and returning that property:

list.stream.map(a -> StringUtils.trimToEmpty(a.getProp())).filter( p -> StringUtils.isNotEmpty(p)).findAny().orElse("");

Do the code above first map all the elements? For efficiency reasons I'd like to process element by element.

答案1

得分: 5

Stream::findAny 是一个短路终端操作,简而言之,如果存在一个项目,它将终止流。

也就是说,如果第一个元素符合 Stream::filter 管道并通过它,Stream::findAny 会立即返回它,而不会处理原始集合中的其他元素。

有一个使用 Stream::peek 来理解 Stream API 如何工作的好例子(假设一个类 Foo 只有一个 final 字符串参数 prop):

List<Foo> list = List.of(
   new Foo(""),           // 第一个是空的,不会通过 Stream::filter
   new Foo("one"),        // 这个是合格的
   new Foo("two"));       // 这个也是合格的

list.stream()
    .peek(item -> System.out.println("# Streamed    " + item.getProp())) // 流式处理
    .map(a -> StringUtils.trimToEmpty(a.getProp()))
    .peek(item -> System.out.println("#  Mapped     " + item))           // 映射
    .filter(StringUtils::isNotEmpty)
    .peek(item -> System.out.println("#   Filtered  " + item))           // 过滤
    .findAny()
    .orElse("");

输出显示第一个元素不会通过 Stream::filter(为空),并在 Stream::map 之前结束。第二个元素通过了 Stream::filter 并且随后的 Stream::map,最终到达了 Stream::findAny。只要 Stream::findAny 是一个具有存在结果的短路终端操作,它就会终止流。

# Streamed    
#  Mapped     
# Streamed    one
#  Mapped     one
#   Filtered  one
英文:

Stream::findAny is a short-circuiting terminal operation, which in a nutshell means that if an item is present, it terminates the Stream.

Ie. if the first element is qualified for the Stream::filter pipe and passes it through, the Stream::findAny returns it immediately without processing further elements in the original collection.

There is a nice proof using Stream::peek to understand how Stream API works (let's say a class Foo has only one final String parameter prop):

List&lt;Foo&gt; list = List.of(
   new Foo(&quot;&quot;),            // the first is empty and doesn&#39;t pass through Stream::filter
   new Foo(&quot;one&quot;),         // this is qualified
   new Foo(&quot;two&quot;));        // this is qualified

list.stream()
    .peek(item -&gt; System.out.println(&quot;# Streamed    &quot; + item.getProp())) // streamed
    .map(a -&gt; StringUtils.trimToEmpty(a.getProp()))
    .peek(item -&gt; System.out.println(&quot;#  Mapped     &quot; + item))           // mapped
    .filter(StringUtils::isNotEmpty)
    .peek(item -&gt; System.out.println(&quot;#   Filtered  &quot; + item))           // filtered
    .findAny()
    .orElse(&quot;&quot;);

The output shows the first element doesn't pass through Stream::filter (is empty) and ended before Stream::map. The second element passed through Stream::filter and the subsequent Stream::map and reached finally Stream::findAny. As long as Stream::findAny is a short-circuiting and terminal operation with a present result, it terminates the Stream.

# Streamed    
#  Mapped     
# Streamed    one
#  Mapped     one
#   Filtered  one

huangapple
  • 本文由 发表于 2020年7月24日 21:32:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/63074620.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定