谈到Stream
,当我执行这段代码时
public class Main {
public static void main(String[] args) {
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));
}
}
我得到了这个输出
A1B1C1
A2B2C2
A3B3C3
因为将我的流限制到前三个组件会强制操作A、B和C只能执行三次。
尝试使用skip()
方法对最后三个元素执行类似的计算,会显示出不同的行为:
public class Main {
public static void main(String[] args) {
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));
}
}
输出以下内容
A1
A2
A3
A4
A5
A6
A7B7C7
A8B8C8
A9B9C9
在这种情况下,为什么要执行从A1到A6的操作?这一定与limit是一个short-circuiting stateful intermediate operation的事实有关,而skip不是,但我不理解这个属性的实际含义。是不是“跳过之前的每个动作都会执行,而限制之前不是每个人都会执行”?
发布于 2015-09-05 22:59:34
这里有两个流管道。
这些流管道每个都由一个源、几个中间操作和一个终端操作组成。
但是中间操作是惰性的。这意味着,除非下游操作需要一个项目,否则什么都不会发生。当它这样做时,那么中间操作完成它所需的所有生成所需的项,然后再次等待,直到另一个项被请求,依此类推。
终端操作通常是“急切”的。也就是说,它们请求流中完成它们所需的所有项。
因此,您应该真正将管道看作是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“peek
需要一个项目,并向limit
输出流请求它,这意味着limit
将需要请求"A”peek
,这将转到源。给出一个项目,然后一直到forEach
,然后得到第一行:
A1B1C1
forEach
请求另一个条目,然后再请求另一个条目。每一次,请求都沿着流向上传播,并执行。但是,当forEach
请求第四个项目时,当请求到达limit
时,它知道它已经提供了允许提供的所有项目。
因此,它不是要求"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
要求第一个项目。这会被传播回来。但是当它到达skip
时,它知道它必须从上游请求6个项目,然后才能通过一个下游项目。因此,它从"A“peek
的上游发出一个请求,在不向下游传递的情况下使用它,然后发出另一个请求,依此类推。因此,"A“窥视得到一个物品的6个请求,并产生6个打印,但这些物品不会被传递。
A1
A2
A3
A4
A5
A6
在skip
发出的第7个请求中,项目被传递到"B“窥视,并从它传递到forEach
,因此完成了完整打印:
A7B7C7
然后就跟以前一样了。现在,每当skip
收到请求时,它都会请求上游的项目,然后将其传递到下游,因为它“知道”它已经完成了跳过的工作。所以剩下的指纹会穿过整个管道,直到来源耗尽。
发布于 2015-09-05 23:07:13
所有的流都是基于拆分器的,拆分器基本上有两种操作: advance (向前移动一个元素,类似于迭代器)和split (将自己分割到任意位置,适合并行处理)。您可以随时停止获取输入元素(这是由limit
完成的),但不能跳到任意位置( Spliterator
接口中没有这样的操作)。因此,skip
操作实际上需要从源文件中读取第一个元素,以便忽略它们。请注意,在某些情况下,您可以执行实际跳转:
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
list.stream().skip(3)... // will read 1,2,3, but ignore them
list.subList(3, list.size()).stream()... // will actually jump over the first three elements
https://stackoverflow.com/questions/32414088
复制相似问题