【发布时间】:2018-05-21 04:02:20
【问题描述】:
谁能告诉我Stream 的中间操作和终端操作有什么区别?
Stream 操作组合成管道来处理流。所有的操作要么是中间的,要么是终端的..means?.
【问题讨论】:
-
流是惰性的,当调用 sum 、 toarray 等终端操作时,代码实际上会做一些事情,而 filter 、 map 是中间的,可能是一个骗子
标签: java java-8 java-stream
谁能告诉我Stream 的中间操作和终端操作有什么区别?
Stream 操作组合成管道来处理流。所有的操作要么是中间的,要么是终端的..means?.
【问题讨论】:
标签: java java-8 java-stream
一个Stream支持多种操作,这些操作分为intermediate和terminal操作。
这些操作的区别在于中间操作是惰性的,而终端操作不是。当您对流调用中间操作时,该操作不会立即执行。它仅在对该流调用终端操作时执行。在某种程度上,中间操作会被记忆,并在调用终端操作时立即调用。您可以链接多个中间操作,在您调用终端操作之前,它们都不会做任何事情。届时,您之前调用的所有中间操作都将与终端操作一起被调用。
所有中间操作都返回 Stream(可以链接),而终端操作不返回。中间操作是:
filter(Predicate<T>)
map(Function<T>)
flatMap(Function<T>)
sorted(Comparator<T>)
peek(Consumer<T>)
distinct()
limit(long n)
skip(long n)
终端操作产生非流(不能链接)结果,例如原始值、集合或根本没有值。
终端操作是:
forEach
forEachOrdered
toArray
reduce
collect
min
max
count
anyMatch
allMatch
noneMatch
findFirst
findAny
最后5个是短路终端操作。
【讨论】:
根据javadoc:
map(MapperFn)或filter(Predicate)
count()或forEach(Consumer)
请注意,所有中间操作将不会在没有终端操作的情况下执行。所以模式将是:
stream()
.intemediateOperation1()
.intemediateOperation2()
...
.intemediateOperationN()
.terminalOperation();
【讨论】:
终端的意思是结束过程,比如收集一个流到一个列表,或者聚合一个值流。
过渡到新状态的中间,在通往终端操作的路上
【讨论】:
您可能注意到,当您定义一个流时,这些方法不仅在整个流上被一个一个地调用,而是它们对流中的每个元素执行一些操作。为了能够并行运行这些流,对于每个元素,基本上都有一个完整的管道。
为了创建多个管道,Java 8+ 使用builder pattern。在每个中间步骤中,您都会将过滤器或转换器添加到堆栈中。为了告诉 Java 从过滤器堆栈生成管道,您使用终止步骤。最后一步结合了所有不同的管道。通常它只是以定义的格式返回值,例如一个列表,但它也可以为每个元素运行一次函数,或者将结果简化为布尔值或数字。
【讨论】:
为了形象化,我们来看看这段代码:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
int sum = numbers.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.reduce(0, Integer::sum);
filter 和 map 是中间操作,reduce 是终端。
numbers.stream()) 创建一个流,所以我们有:
|1,2,3,4|numbers.stream().filter(n -> n % 2 == 0)):
|1,2,3,4| ----- |过滤器|numbers.stream().filter(n -> n % 2 == 0).map(n -> n * n)):
|1,2,3,4| ----- |过滤器| ----- |地图|reduce,是终端操作,整个流程运行:
|1,2,3,4| -> 4 3 2 1 -> |过滤器| -> 4 2 -> |地图| -> 16 4 -> |减少| -> 20请注意,在调用终端操作之前,没有数据流过流。
【讨论】: