【问题标题】:Java 8 Stream - Filter and foreach method not printing as expectedJava 8 Stream - 过滤器和 foreach 方法未按预期打印
【发布时间】:2016-11-29 10:40:25
【问题描述】:

我正在执行以下程序:

Stream.of("d2", "a2", "b1", "b3", "c")
.filter(s -> {
    System.out.println("filter: " + s);
    return true;
})
.forEach(s -> System.out.println("forEach: " + s));

我得到的输出是:

filter:  d2
forEach: d2
filter:  a2
forEach: a2
filter:  b1
forEach: b1
filter:  b3
forEach: b3
filter:  c
forEach: c

但是,我期待以下输出:

filter:  d2
filter:  a2
filter:  b1
filter:  b3
filter:  c 
forEach: d2
forEach: a2
forEach: b1
forEach: b3
forEach: c

意思是,首先filter 方法循环应该已经完全执行,然后forEach 方法循环应该已经开始。

是不是我做错了什么?

【问题讨论】:

标签: java java-8 java-stream


【解决方案1】:

你的期望是错误的。

当终端操作forEach被执行时,它一次消耗Stream的一个元素。它消耗的每个元素都必须传递Stream 的所有中间操作,这会导致filter 在同一元素上执行forEach 之前在该元素上执行(假设该元素通过filter)。

换句话说,当Stream 管道中的下一个操作需要它的下一个元素时,filter 会延迟应用于每个元素(在您的情况下,下一个操作是forEach)。

这意味着如果您的终端操作只需要处理某些 Stream 元素(例如,如果您将 forEach() 替换为 findFirst()),则 filter() 操作将只执行到第一个元素通过它(在您的示例中,这意味着过滤器将仅针对第一个元素执行)。

【讨论】:

    【解决方案2】:

    Stream 的处理将从一个终端操作开始,并一个接一个地消费。优点是:

    程序必须只计算相关项 - 例如,如果只需要一项,filter 只会被调用一次:

    Stream.of("d2", "a2", "b1", "b3", "c")
    .filter(s -> {
        System.out.println("filter: " + s);
        return true;
    })
    .findAny()
    .ifPresent(s -> System.out.println("forEach: " + s));
    

    输出:

    filter: d2
    forEach: d2
    

    您甚至可以创建 infinte 流(否则这是不可能的):

    IntStream.iterate(0, i -> i+1)
    .filter(s -> {
        System.out.println("filter: " + s);
        return true;
    })
    .peek(i -> {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
    })
    .forEach(s -> System.out.println("forEach: " + s));
    

    输出:

    filter: 0
    forEach: 0
    filter: 1
    forEach: 1
    ... (up to infinity)
    

    【讨论】:

      猜你喜欢
      • 2018-06-19
      • 1970-01-01
      • 1970-01-01
      • 2017-04-13
      • 2011-05-22
      • 1970-01-01
      • 2017-09-08
      • 1970-01-01
      • 2017-04-13
      相关资源
      最近更新 更多