在同一流上重复forEach()-为什么不行?

时间:2019-03-30 09:47:59

标签: java java-8 java-stream

1)为什么恰好第二个forEach()不起作用?确切的规则是什么?

2)如何重置流以再次在其上运行forEach?我是否总是需要创建另一个IntStream sm2 = str.chars();之类的IntStream实例才能在sm2(sm2.forEach(...))上工作,还是有一种方法可以“重置” sm?

String str = "A B C D";
IntStream sm = str.chars();

sm.forEach(System.out::println); // works

// IllegalStateException: stream has already been operated upon or closed
sm.forEach(ch -> System.out.println(ch)); 

P.S。我知道forEach()终端操作,但是我了解到forEach()不会返回流=>我无法链接调用,无法回答我的问题问题(我不需要将任何进一步的呼叫用点链接起来的情况都链接起来)。

3 个答案:

答案 0 :(得分:1)

第一个forEach循环已清空该流。如果要重复使用forEach循环,则必须复制原始流或数据。您可以使用相同的数据创建另一个流:

IntStream sm = str.chars();

sm.forEach(System.out::println); // works

sm = str.chars();

sm.forEach(ch -> System.out.println(ch)); // works

答案 1 :(得分:0)

这是流的核心概念。流是可能是无限的数据的集合。因此,为了提高内存效率,我们无法将所有元素都保存在内存中。

流可以看作是“一个元素+获取下一个元素的方法”。因此,如果您遍历所有流,则“不知道”如何再次进行遍历,因为该信息已被丢弃。

如果您需要迭代多次,请选择另一个集合(列表?)

答案 2 :(得分:0)

总是有一个Stream::peek方法,该方法确实执行Consumer操作并且是非终结性的。但是,正如文档所述:

  

此方法主要用于支持调试,您希望在其中查看元素流过管道中特定点的情况

所以我不确定这是否完全适合您。您可以在此处了解更多信息:In Java streams is peek really only for debugging?

因此,我建议仅在单个forEach中执行任何您想执行的操作:

stream.forEach(e -> {
    operation1(e);
    operation2(e);
});

forEach关闭流的原因-仅仅是因为API是这样设计的。 :)