在过滤器 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 之前,地图是不是应用于所有列表?的主要内容,如果未能解决你的问题,请参考以下文章