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

Is map applied on all the list before filter findAny?

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

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

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

Stream::findAny is a short-circuiting terminal operation,简而言之,如果输入是,它会终止 Stream。

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

有一个使用 Stream::peek 的很好的证明来理解 Stream API 是如何工作的(假设 class 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