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

时间:2018-03-31 13:37:28

标签: java java-8 java-stream elements

Java 8 Stream API中,filtermappeek等中间操作的说明被称为

  

...此流的元素......

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

filter的API描述是

  

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

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

感谢。

3 个答案:

答案 0 :(得分:4)

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

例如:

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

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

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

  

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

"返回一个流"因为每个中间操作都会返回一个新流

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

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

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

作为一个阅读,Brian Goetz关于Streams under the hood的帖子很精彩。这真的是关于流的详细信息,有一个很好的动画由Tagir Valeev提供,它展示了如何可视化流。

答案 1 :(得分:3)

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

请参阅以下相同的签名:

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

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

规范也是如此:

  

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

答案 2 :(得分: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());

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