Java流操作融合和有状态中间操作

Tra*_*ity 10 java sorted stateful java-8 java-stream

我一直试图理解和展示Java流如何在引擎盖下实现一种循环融合,以便将几个操作融合到一个通道中.

这是第一个例子:

Stream.of("The", "cat", "sat", "on", "the", "mat")
        .filter(w -> {
            System.out.println("Filtering: " + w);
            return w.length() == 3;
        })
        .map(w -> {
            System.out.println("Mapping: " + w);
            return w.toUpperCase();
        })
        .forEach(w -> System.out.println("Printing: " + w));
Run Code Online (Sandbox Code Playgroud)

具有以下输出(每个元素的单个传递的融合非常清晰):

Filtering: The
Mapping: The
Printing: THE
Filtering: cat
Mapping: cat
Printing: CAT
Filtering: sat
Mapping: sat
Printing: SAT
Filtering: on
Filtering: the
Mapping: the
Printing: THE
Filtering: mat
Mapping: mat
Printing: MAT
Run Code Online (Sandbox Code Playgroud)

第二个例子是相同的,但我使用filter和map之间的sorted()操作:

Stream.of("The", "cat", "sat", "on", "the", "mat")
        .filter(w -> {
            System.out.println("Filtering: " + w);
            return w.length() == 3;
        })
        .sorted()
        .map(w -> {
            System.out.println("Mapping: " + w);
            return w.toUpperCase();
        })
        .forEach(w -> System.out.println("Printing: " + w));
Run Code Online (Sandbox Code Playgroud)

这有以下输出:

Filtering: The
Filtering: cat
Filtering: sat
Filtering: on
Filtering: the
Filtering: mat
Mapping: The
Printing: THE
Mapping: cat
Printing: CAT
Mapping: mat
Printing: MAT
Mapping: sat
Printing: SAT
Mapping: the
Printing: THE
Run Code Online (Sandbox Code Playgroud)

所以我的问题在这里,通过调用distinct,我认为因为它是一个"有状态"的中间操作,所以它不允许在单个传递(所有操作)中单独处理单个元素.此外,因为sorted()有状态操作需要处理整个输入流以产生结果,所以这里不能部署融合技术,这就是为什么所有的过滤首先发生,然后它将映射和打印操作融合在一起的原因,排序后?如果我的任何假设不正确,请纠正我,并随时详细说明我已经说过的内容.

此外,它如何决定它是否可以将元素融合到一个通道中,例如,当存在distinct()操作时,是否只有一个标志可以关闭以阻止它发生,就像它一样什么时候distinct()不存在?

最后的问题是,虽然将操作融合到单个通道中的好处有时是显而易见的,例如,当与短路结合时.将操作融合在一起的主要好处是什么,例如filter-map-forEach,甚至是filter-map-sum?

Bri*_*etz 14

无状态操作(地图,过滤器,flatMap,PEEK等)完全融合; 我们建立了一系列级联Consumer对象并将数据倒入.每个元素可以彼此独立地操作,因此链中永远不会"卡住".(这就是路易斯的意思是如何实现融合 - 我们将这些阶段组合成一个大功能,然后将数据提供给它.)

有状态操作(不同的,排序的,限制的等)更复杂,并且其行为的变化更大.每个有状态操作都可以选择它想要实现的方式,因此它可以选择可能性最小的方法.例如,distinct(在某些情况下),让元素在审查时出现,而sorted完全屏障.(不同之处在于可能存在多少懒惰,以及它们如何处理下游限制操作的无限来源.)

确实,有状态操作通常会破坏融合的一些好处,但并非所有这些好处(上游和下游的操作仍然可以融合).

除了您观察到的短路值之外,融合的额外大赢还包括(a)您不必在阶段之间填充中间结果容器,以及(b)您正在处理的数据总是"热" "在缓存中.