英文:
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<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("");
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论