在过滤器 findAny 之前,地图是不是应用于所有列表?

Posted

技术标签:

【中文标题】在过滤器 findAny 之前,地图是不是应用于所有列表?【英文标题】:Is map applied on all the list before filter findAny?在过滤器 findAny 之前,地图是否应用于所有列表? 【发布时间】:2020-11-14 09:09:30 【问题描述】:

我想为具有非 null 属性的元素过滤列表并返回该属性:

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

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

【问题讨论】:

不行,map操作偷懒,在pipeline中一一进行 所以它起作用了:如果 prop 不为空,它将停止到第一个映射? 是的,请参阅@Nikolas 回答中的详细信息 与其他更传统的方法相比,这实际上是流式传输的核心原则和优势之一。大多数操作都是“懒惰的”,只建立一个操作管道。一旦您进行了终端操作,元素就会通过管道一个一个地发送,而不是之前。 【参考方案1】:

Stream::findAny 是一个short-circuiting terminal operation,简而言之,这意味着如果输入是它会终止 Stream。

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

有一个很好的证明使用Stream::peek 来理解Stream API 的工作原理(假设一个类Foo 只有一个最终的字符串参数prop):

List<Foo> list = List.of(
   new Foo(""),            // the first is empty and doesn't pass through Stream::filter
   new Foo("one"),         // this is qualified
   new Foo("two"));        // this is qualified

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

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

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

【讨论】:

以上是关于在过滤器 findAny 之前,地图是不是应用于所有列表?的主要内容,如果未能解决你的问题,请参考以下文章

使用无注解属性的过滤

Java8-stream findAny()注意点

java8 stream接口 终端操作 min,max,findFirst,findAny

Spark - 地图转换

没有对应于所需形式参数的参数

地图服务器空间过滤