理解java Stream.limit() 操作

ani*_*nir 3 java functional-programming java-stream

我在学习Stream.limit()说道:

返回由该流的元素组成的流,其长度被截断为不超过 maxSize。

这可以理解为:

Stream.of(1,2,3,4,5,6,7,8)
    .limit(3)
    .forEach(i -> {
        System.out.print(i + ",");
    });  //prints: 1,2,3,
Run Code Online (Sandbox Code Playgroud)

但是当与其他流方法一起使用时,它具有批量处理元素的效果:

Stream.of(1,2,3,4,5,6,7)
    .filter(i -> {
        System.out.println("Filtering "  + i + ": " + (i%2 == 0));
        return i%2 == 0;
    })
    .map(i-> {
        System.out.println("Mapping " + i + " to " + i*i);
        return i*i;
    })
    .limit(2)
    .forEach(i -> System.out.println("---> " + i));
Run Code Online (Sandbox Code Playgroud)

印刷:

Filtering 1: false
Filtering 2: true
Mapping 2 to 4
---> 4
Filtering 3: false
Filtering 4: true
Mapping 4 to 16
---> 16
Run Code Online (Sandbox Code Playgroud)

在这里,您可以看到元素以 2 为一组进行处理。

我有以下疑问:

  1. 为什么它不只处理前两个元素 1 和 2?也就是说,为什么输出不仅仅是:

     Filtering 1: false
     Filtering 2: true
     Mapping 2 to 4
     ---> 4
    
    Run Code Online (Sandbox Code Playgroud)
  2. 为什么它没有处理最后四个元素 5、6、7 和 8 并打印以下内容?:

     Filtering 5: false
     Filtering 6: true
     Mapping 6 to 36
     ---> 36
     Filtering 7: false
     Filtering 8: true
     Mapping 8 to 64
     ---> 64
    
    Run Code Online (Sandbox Code Playgroud)

Kar*_*cki 5

  1. 双方12进行了处理。1很奇怪,因此filter将其从流管道中删除。2是偶数并通过整个流管道导致4forEach.

  2. 流本质上是惰性的。由于您limit(2)只使用了两个元素,因此将通过limit管道步骤。24通过整个流管道导致416forEach.

limit()根据文档,是短路状态中间操作:

limit(n) 或 findFirst() 等短路操作可以允许在有限的时间内完成对无限流的计算。

...

此外,一些操作被视为短路操作。如果中间操作在呈现无限输入时可能因此产生有限流,则它是短路的。如果终端操作在无限输入时可能在有限时间内终止,则它是短路的。在管道中进行短路操作是无限流处理在有限时间内正常终止的必要条件,但不是充分条件。

  • @anir,Java Stream API 以“拉方式”工作,而不是“推方式”。这意味着它首先评估最后一个操作,然后在链中最后评估第一个操作。并且因为这是'pull-way',所以没有任何方法可以'pull'比'limit'阶段定义的更多的元素。 (2认同)