Java 8 Stream 中间操作 - 元素处理

5
Java 8 Stream API 中,中间操作(如 filtermappeek)的描述被称为“...此流的元素...”。但是,像 filter 这样的流中间操作似乎会一次处理并返回一个单独的“元素”。例如,Java 8 stream operations execution order 问题(请参见输出)和答案。 filter 的 API 描述为“返回由与给定谓词匹配的此流的元素组成的流”。但是,Java 8 stream operations execution order 问题中提到的代码似乎会一次处理并返回单个元素。请澄清 API 中“元素”和代码中明显处理单个“元素”的不一致之处。
谢谢。

如答案评论中所提到的 - 我理解返回类型是Stream,但是为什么API使用“此流的元素”而不是“此流的元素”。 换句话说,为什么API在元素上使用复数形式? - lupchiazoem
因为流表示元素序列,在大多数情况下,有多个元素通过给定的中间操作。 - Ousmane D.
3个回答

6

是的,无状态的中间操作,如filtermap等,每次处理一个给定元素,前者将其发送到下一阶段(即流管道中的下一个中间操作),而后者在调用映射函数后始终将元素发送到后续操作。

例如:

...
.filter(n -> n % 2 == 0) // retain even numbers
.map(n -> n * n) // square it
...

一次只有一个元素会通过过滤操作,如果当前元素符合提供的谓词,则传递到映射操作。
我认为你理解了这部分内容,但是你可能困惑的是为什么在java文档中写道:
“返回由与给定谓词匹配的此流的元素组成的流。”
“返回一个流”,因为每个中间操作都返回一个新的流
“由元素组成”,因为流表示元素的序列,在大多数情况下,有多个元素通过给定的中间操作。
这听起来像流存储它的元素,但实际上并不是这样。相反,它们可以存储在某些底层集合中或按需生成。
值得注意的是,并不是每个中间操作都会一次将一个元素传递到下一个阶段。例如,sorted 中间操作会缓冲所有元素,直到它看到输入的结尾,然后将数据发送到后续阶段。
作为一篇阅读材料,Brian Goetz 写了一篇关于 流(Streams)底层实现 的精彩文章。这篇文章详细介绍了流(Streams)的相关内容,并且有一个很好的动画演示来自 Tagir Valeev,展示了如何可视化流(Streams)。

3
相比我选择的答案,这个回答有更好的解释和深入见解。 - lupchiazoem

3

我认为这里存在一些误解,因为过滤器总是返回流。

请查看以下签名:

 Stream<T> filter(Predicate<? super T> predicate);

因此,任何这样的中间操作都会返回流而不是一个元素,您可以像在流上执行的所有操作一样在它们上执行所有操作。

规范也是如此:

返回由与给定谓词匹配的此流的元素组成的流。


1
我知道返回类型是Stream,但API为什么提到“这个流的元素”,而不是“这个流的元素”呢?换句话说,为什么API在元素上使用复数形式? - lupchiazoem
1
根据规范,返回一个流,其中包含与给定谓词匹配的此流的元素。这意味着基于谓词,它包括原始流中的多个元素,因此是复数形式。 - Aman Chhabra
1
是的,就像你所提到的那样,有一些误解。我认为你的回答和评论很有道理。我已经点赞了两者。 - lupchiazoem

1
“map”和“filter”中间操作确实会对流中的每个元素执行,但它们会为自己返回一个新的流。
因此,当我们查看上述问题的代码时,筛选操作将对1-8的每个数字执行,但它将返回一个仅观察偶数{2,4,6,8}的新流。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
List<Integer> twoEvenSquares = numbers.stream().filter(n -> {
    System.out.println("filtering " + n);
    return n % 2 == 0;
}).map(n -> {
    System.out.println("mapping " + n);
    return n * n;
}).limit(2).collect(Collectors.toList());

没有断开,因为就像Stream 8 Stream API所说的那样,中间操作符例如filter(Function<?, Boolean> filteringFunction)会返回一个Stream。它们通过在输入流中对每个元素执行给定的filteringFunction,并返回一个新的输出流,只观察已被过滤为true的元素。


8
有一点需要注意。流中没有元素。流只是一个连接到源并查看元素流动的对象。 - Ousmane D.
谢谢您澄清这个问题,我将编辑我的答案。 - Georg Muehlenberg
1
@Aominè 评论得好,甚至 Stream#of 基于 SpinedBuffer - Eugene

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接