在Java 8 Stream API中,filter
,map
和peek
等中间操作的说明被称为
...此流的元素......
但是,像filter
这样的流中间操作似乎一次处理并返回一个单独的'元素'。例如,Java 8 stream operations execution order提问(请参阅输出)和答案。
filter
的API描述是
返回一个流,该流由与该给定谓词匹配的此流的元素组成。
但是,Java 8 stream operations execution order问题中提到的代码似乎一次处理并返回一个单独的元素。请澄清API提及“元素”与代码中单个“元素”的明显处理之间的脱节。
感谢。
答案 0 :(得分:4)
是的,无状态中间操作,例如filter
,map
等,一次处理一个给定的元素,而前者或者是否将它发送到下一个阶段,下一个阶段是流管道中的后续中间操作。后者将始终在调用映射函数后将元素发送到后续操作。
例如:
...
.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)
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
的元素。