首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Java 8 Stream: limit()和skip()之间的区别

Java 8 Stream: limit()和skip()之间的区别
EN

Stack Overflow用户
提问于 2015-09-05 22:17:06
回答 2查看 52.4K关注 0票数 66

谈到Stream,当我执行这段代码时

代码语言:javascript
复制
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));
    }
}

我得到了这个输出

代码语言:javascript
复制
A1B1C1
A2B2C2
A3B3C3

因为将我的流限制到前三个组件会强制操作A、B和C只能执行三次。

尝试使用skip()方法对最后三个元素执行类似的计算,会显示出不同的行为:

代码语言:javascript
复制
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));
    }
}

输出以下内容

代码语言:javascript
复制
A1
A2
A3
A4
A5
A6
A7B7C7
A8B8C8
A9B9C9

在这种情况下,为什么要执行从A1到A6的操作?这一定与limit是一个short-circuiting stateful intermediate operation的事实有关,而skip不是,但我不理解这个属性的实际含义。是不是“跳过之前的每个动作都会执行,而限制之前不是每个人都会执行”?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-09-05 22:59:34

这里有两个流管道。

这些流管道每个都由一个源、几个中间操作和一个终端操作组成。

但是中间操作是惰性的。这意味着,除非下游操作需要一个项目,否则什么都不会发生。当它这样做时,那么中间操作完成它所需的所有生成所需的项,然后再次等待,直到另一个项被请求,依此类推。

终端操作通常是“急切”的。也就是说,它们请求流中完成它们所需的所有项。

因此,您应该真正将管道看作是forEach向它后面的流请求下一项,然后该流向它后面的流请求,依此类推,一直到源。

考虑到这一点,让我们看看我们在第一个管道中有什么:

代码语言:javascript
复制
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,然后得到第一行:

代码语言:javascript
复制
A1B1C1

forEach请求另一个条目,然后再请求另一个条目。每一次,请求都沿着流向上传播,并执行。但是,当forEach请求第四个项目时,当请求到达limit时,它知道它已经提供了允许提供的所有项目。

因此,它不是要求"A“偷看另一件物品。它立即指示它的项已耗尽,因此,不再执行任何操作,forEach终止。

在第二个管道中发生了什么?

代码语言:javascript
复制
    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个打印,但这些物品不会被传递。

代码语言:javascript
复制
A1
A2
A3
A4
A5
A6

skip发出的第7个请求中,项目被传递到"B“窥视,并从它传递到forEach,因此完成了完整打印:

代码语言:javascript
复制
A7B7C7

然后就跟以前一样了。现在,每当skip收到请求时,它都会请求上游的项目,然后将其传递到下游,因为它“知道”它已经完成了跳过的工作。所以剩下的指纹会穿过整个管道,直到来源耗尽。

票数 103
EN

Stack Overflow用户

发布于 2015-09-05 23:07:13

所有的流都是基于拆分器的,拆分器基本上有两种操作: advance (向前移动一个元素,类似于迭代器)和split (将自己分割到任意位置,适合并行处理)。您可以随时停止获取输入元素(这是由limit完成的),但不能跳到任意位置( Spliterator接口中没有这样的操作)。因此,skip操作实际上需要从源文件中读取第一个元素,以便忽略它们。请注意,在某些情况下,您可以执行实际跳转:

代码语言:javascript
复制
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
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32414088

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档