【问题标题】:Java 8 Stream intermediate operation - element processingJava 8 Stream 中间操作——元素处理
【发布时间】:2018-03-31 13:37:28
【问题描述】:

Java 8 Stream API 中,对filtermappeek 等中间操作的描述被提及为

...这个流的元素...

但是,像filter 这样的流中间操作似乎一次处理并返回一个单独的“元素”。例如,Java 8 stream operations execution order 问题(见输出)和答案。

filter的API描述是

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

但是,Java 8 stream operations execution order 问题中提到的代码似乎一次处理并返回一个单独的元素。请澄清 API 提及“元素”与对代码的单个“元素”的明显处理之间的脱节。

谢谢。

【问题讨论】:

  • 正如评论中提到的答案 - 我知道返回类型是 Stream 但是,为什么 API 提到 - “这个流的元素”而不是“这个流的元素”。 IOW,为什么 API 使用复数表示元素?
  • 因为流表示一系列元素,并且在大多数情况下,有多个元素通过给定的中间操作。

标签: java java-8 java-stream elements


【解决方案1】:

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

例如:

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

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

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

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

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

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

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


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


作为阅读,Brian Goetz 有一篇关于Streams under the hood 的精彩帖子。这确实涉及有关流的细节,Tagir Valeev 提供了一个很好的动画,展示了如何可视化流。

【讨论】:

  • 与我选择的答案相比,这个答案有更好的解释和洞察力。
【解决方案2】:

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

请参阅以下相同的签名:

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

因此,任何此类中间操作一次返回流而不是一个元素,您可以对它们执行所有操作,就像对流执行一样。

规范也是如此:

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

【讨论】:

  • 我知道返回类型是 Stream 但是,为什么 API 提到 - “这个流的元素”而不是“这个流的元素”。 IOW,为什么 API 使用复数表示元素?
  • 根据规范,返回一个由与给定谓词匹配的该流的元素组成的流。这意味着这包括基于谓词的原始流中的多个元素,因此是复数。
  • 是的,正如您所提到的,存在误解。你的回答和评论是有道理的,因为我允许事情下沉。两者都赞成。
【解决方案3】:

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());

没有断开连接,因为就像 Stream 8 Stream API 所说,filter(Function&lt;?, Boolean&gt; filteringFunction) 等中间运算符返回一个 Stream。他们通过对 in-stream 的每个元素执行给定的 filteringFunction 来做到这一点,并返回一个新的 out-stream,它只观察已过滤到 true 的元素。

【讨论】:

  • 有一点需要注意。 in 流中没有元素。流只是一个连接到源并查看元素的对象 flow.
  • 感谢您澄清这一点,我将编辑我的答案。
  • @Aominè 好评,连Stream#of 都是基于SpinedBuffer
猜你喜欢
  • 2014-08-14
  • 1970-01-01
  • 1970-01-01
  • 2017-11-06
  • 1970-01-01
  • 2017-09-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多