你在这里有两个流水线。

这些流管线每个包括源,几个中间操作和终端操作。

但中间操作是懒惰的。这意味着除非下游操作需要项目,否则什么都不发生。当它存在时,中间操作完成它需要产生所需的项目,然后再次等待,直到请求另一个项目,等等。

终端操作通常是“渴望”。也就是说,他们要求流中需要它们完成的所有项目。

所以你应该真正把管道看作是forEach要求下一个项目的流,并且该流询问它后面的流,等等,一直到源。

考虑到这一点,让我们看看我们有你的第一条管道:

Stream.of(1,2,3,4,5,6,7,8,9)
.peek(x->System.out.print("\nA"+x))
.limit(3)
.peek(x->System.out.print("B"+x))
.forEach(x->System.out.print("C"+x));

所以,forEach要求第一个项目。这意味着“B”窥探需要一个项目,并要求限制输出流为它,这意味着极限将需要询问“A”窥视,它去源。一个项目给出,一直到forEach,你得到你的第一行:

A1B1C1

forEach要求另一个项目,然后另一个。并且每次,请求都向上传播流,并执行。但是当forEach请求第四个项目时,当请求达到限制时,它知道它已经给出了它允许给出的所有项目。

因此,它不是要求“A”偷看另一个项目。它立即指示其项目已用尽,因此,不再执行任何动作,并且forEach终止。

第二个管道会发生什么?

Stream.of(1,2,3,4,5,6,7,8,9)
.peek(x->System.out.print("\nA"+x))
.skip(6)
.peek(x->System.out.print("B"+x))
.forEach(x->System.out.print("C"+x));

再次,forEach要求第一个项目。这被传播回来。但是当它到达跳跃时,它知道它必须从其上游请求6个项目,然后它可以通过一个下游。因此,它从“A”窥视向上游请求,消耗它而不向下游传递,提出另一个请求,等等。因此,“A”窥视获得一个项目的6个请求,并产生6个打印,但这些项目不会传递下来。

A1

A2

A3

A4

A5

A6

在跳过的第7个请求,项目被传递到“B”窥视和从它到forEach,所以完整的打印完成:

A7B7C7

然后就像以前一样。跳过现在,每当它获得请求,请求一个项目上游,并将其传递到下游,因为它“知道”它已经完成其跳过作业。因此,其余的打印正在通过整个管道,直到源耗尽。