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

lup*_*oem 5 java element java-8 java-stream

Java 8 Stream APIfilter中,对 、和map等中间操作的描述peek被提及为

...该流的元素...

但是,流式中间操作似乎filter一次处理并返回一个单独的“元素”。例如,Java 8 流操作执行顺序问题(参见输出)和答案。

API 描述filter

返回一个由该流中与给定谓词匹配的元素组成的流。

但是, Java 8 流操作执行顺序问题中提到的代码似乎一次处理并返回一个单独的元素。请澄清 API 提及的“元素”与代码中单个“元素”的明显处理之间的脱节。

谢谢。

Ous*_* D. 6

是的,诸如 等的无状态中间操作filter一次map处理给定的元素,前者要么将其发送到下一个阶段,要么不将其发送到下一个阶段,其中下一个阶段是流管道中的后续中间操作。后者总是在调用映射函数后将元素发送到后续操作。

例如:

...
.filter(n -> n % 2 == 0) // retain even numbers
.map(n -> n * n) // square it
...
Run Code Online (Sandbox Code Playgroud)

一次一个元素将通过该filter操作,如果当前元素满足所提供的谓词,则会将其传递给该map操作。

我认为你理解这部分,但你的困惑是为什么在java文档中这么写:

返回一个由该流中与给定谓词匹配的元素组成的流。

“返回一个流”,因为每个中间操作都会返回一个新的流

“由元素组成”,因为流表示元素序列,并且在大多数情况下,有多个元素通过给定的中间操作。

这听起来像是流存储其元素,但事实并非如此。相反,它们可能存储在某些底层集合中或按需生成。


值得注意的是,并非每个中间操作都会一次将一个元素传递到下一阶段。例如,sorted中间操作缓冲所有元素,直到看到输入结束,然后将数据发送到后续阶段。


作为读物,Brian Goetz发表了一篇关于Streams 底层的精彩文章。这确实涉及到有关流的详细信息,并且Tagir Valeev提供了一个很好的动画,展示了如何可视化流。

  • 与我选择的答案相比,这个答案有更好的解释和见解。 (3认同)

Geo*_*erg 1

和中间操作确实在流的每个元素上执行,但它们自己返回一个流mapfilter

因此,当我们查看上一个问题中的代码时,将对每个数字 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());
Run Code Online (Sandbox Code Playgroud)

没有断开连接,因为就像 Stream 8 Stream API 所说的那样,中间操作符会filter(Function<?, Boolean> filteringFunction)返回一个 Stream。他们通过对输入流的每个元素执行给定的操作filteringFunction并返回一个新的输出流来实现这一点,该输出流仅观察已过滤到的元素true

  • 但有一点需要注意。流中没有元素。流只是一个连接到源并查看元素_流_的对象。 (8认同)