Java流是连续阶段的吗?

Bog*_*lga 14 java lambda java-8 java-stream

我对中间阶段的顺序的状态的问题-从施加到一个阶段的操作的所有输入流(项目)是所有级/操作施加到各流项目?

我知道这个问题可能不容易理解,所以我举一个例子.在以下流处理中:

List<String> strings = Arrays.asList("Are Java streams intermediate stages sequential?".split(" "));
strings.stream()
           .filter(word -> word.length() > 4)
           .peek(word -> System.out.println("f: " + word))
           .map(word -> word.length())
           .peek(length -> System.out.println("m: " + length))
           .forEach(length -> System.out.println("-> " + length + "\n"));
Run Code Online (Sandbox Code Playgroud)

我对这段代码的期望是它会输出:

f: streams
f: intermediate
f: stages
f: sequential?

m: 7
m: 12
m: 6
m: 11

-> 7
-> 12
-> 6
-> 11
Run Code Online (Sandbox Code Playgroud)

相反,输出是:

f: streams
m: 7
-> 7

f: intermediate
m: 12
-> 12

f: stages
m: 6
-> 6

f: sequential?
m: 11
-> 11
Run Code Online (Sandbox Code Playgroud)

由于控制台输出,这些项目是否仅针对所有阶段显示?或者,他们也处理的所有阶段,一次一个?

如果问题不够明确,我可以进一步详细说明这个问题.

Ous*_* D. 20

此行为可以优化代码.如果每个中间操作都要在进行下一个中间操作之前处理流的所有元素,那么就没有优化的可能性.

因此,为了回答您的问题,每个元素一次一个地垂直移动流管道(除了稍后讨论的一些有状态操作),因此在可能的情况下实现优化.

说明

根据您提供的示例,每个元素将沿着流管道一个接一个地垂直移动,因为不包含有状态操作.

另一个例子,假设你正在寻找String长度大于的第一个,4在提供结果之前处理所有元素是不必要和耗时的.

考虑这个简单的例子:

List<String> stringsList = Arrays.asList("1","12","123","1234","12345","123456","1234567");
int result = stringsList.stream()
                        .filter(s -> s.length() > 4)
                        .mapToInt(Integer::valueOf)
                        .findFirst().orElse(0);
Run Code Online (Sandbox Code Playgroud)

filter上述中间操作将无法找到所有的长度大于元素4,并返回他们的新的流,而是会发生什么,只要我们找到的第一个单元,其长度大于是4,该元素经过的.mapToInt,然后findFirst说: "我找到了第一个元素"并且执行在那里停止.因此结果将是12345.

有状态和无状态中间操作的行为

注意,当诸如此类的有状态中间操作sorted包括在流管道中时,该特定操作将遍历整个流.如果你考虑一下,这就完全合情合理,因为你需要对元素进行排序,以查看所有元素,以确定哪些元素在排序顺序中排在第一位.

distinct中间操作也是状态操作,但是,由于@Holger已经不像提到的sorted,它不需要遍历整个流为每个不同的元素可以立即得到流传下来的管道,可以实现一个短路条件.

如上所述filter,诸如map等的无状态中间操作不必遍历整个流并且可以一次一个地自由地处理一个元素.

最后,但同样重要的是要注意,当终端操作是短路操作时,终端短路方法可以在遍历底层流的所有元素之前完成.

阅读:Java 8流教程