Java 8 Stream中的forEach vs forEachOrdered


86

我知道这些方法的执行顺序不同,但是在我所有的测试中,我无法实现不同的执行顺序。

例:

System.out.println("forEach Demo");
Stream.of("AAA","BBB","CCC").forEach(s->System.out.println("Output:"+s));
System.out.println("forEachOrdered Demo");
Stream.of("AAA","BBB","CCC").forEachOrdered(s->System.out.println("Output:"+s));

输出:

forEach Demo
Output:AAA
Output:BBB
Output:CCC
forEachOrdered Demo
Output:AAA
Output:BBB
Output:CCC

请提供示例,说明两种方法将产生不同的输出。


尝试使用并行流。
Pshemo

@Pshemo是唯一的选择吗?
gstackoverflow

5
未指定的顺序并不意味着“保证为不同的顺序”。它只是表示unspecified,这始终意味着可以匹配遇到顺序。没有内置的随机播放功能。
Holger 2015年

Answers:


89
Stream.of("AAA","BBB","CCC").parallel().forEach(s->System.out.println("Output:"+s));
Stream.of("AAA","BBB","CCC").parallel().forEachOrdered(s->System.out.println("Output:"+s));

第二行将始终输出

Output:AAA
Output:BBB
Output:CCC

而第一个不保证,因为不保留顺序。forEachOrdered将按照其源指定的顺序处理流的元素,而不管该流是顺序的还是并行的。

引用forEachJavadoc:

该操作的行为明确地是不确定的。对于并行流管道,此操作不能保证尊重流的遇到顺序,因为这样做会牺牲并行性的好处。

forEachOrderedJavadoc声明时(强调我的意思):

如果流具有定义的遇到顺序,则按流的遇到顺序对此流的每个元素执行操作。


6
你是对的。只能用于parallelStreams吗?
gstackoverflow

6
即使它现在仅适用于并行流-而且我不是说它也适用-如果某些中间步骤得到优化以利用无序流,则它将来可能仍然会中断,例如,如果流是无序的。
the8472 2015年

1
因此,将其forEachOrderedparallel
Bhushan

3
@BhushanPatil是的,这是正确的。stackoverflow.com/questions/47336825/…–
Sagar

1
使用forEachOrdered将按顺序处理元素,然后使用并行流将失去并行性的好处。请提出建议。
迪帕克

30

尽管forEach更短并且看上去更漂亮,但我建议forEachOrdered在顺序很重要的每个地方都使用它来明确指定它。对于顺序流,forEach似乎遵守顺序,甚至流API内部代码使用 forEach(对于已知为顺序的流)在语义上必须使用forEachOrdered!但是,您稍后可能会决定将流更改为并行,并且代码将被破坏。同样,当您使用forEachOrdered代码阅读器时,也会看到消息:“顺序在这里很重要”。因此,它可以更好地记录您的代码。

还要注意,对于并行流,forEach不仅要以不确定的顺序执行,而且还可以针对不同的元素在不同的线程中同时执行它(使用不可能forEachOrdered)。

最后,两个forEach/forEachOrdered很少有用。在大多数情况下,您实际上需要产生一些结果,而不仅仅是副作用,因此类似reducecollect应该更合适的操作。通过表现自然还原操作forEach通常被认为是一种不好的方式。


7
“最后两个forEach / forEachOrdered都很少有用”。我十分同意。这些方法似乎被过度使用。
Tunaki 2015年

感谢您的回答。但这不是现实生活中的例子。我只是学习Java 8
gstackoverflow

为什么在语义上必须forEachOrdered在该代码中使用?
RealSkeptic 2015年

1
@RealSkeptic,它是用户指定的流(传递到flatMap)。它可以排序,因此必须以相同的顺序放入结果流中。
塔吉尔·瓦列夫2015年

2
@RealSkeptic,您是真正的怀疑论者!Stream.of("a", "b", "c").flatMap(s -> Stream.of("1", "2", "3").map(s::concat)).spliterator().hasCharacteristics(Spliterator.ORDERED)返回true,因此必须确定结果流的顺序。如果您认为JDK文档应该明确说明这一点,请随时提交错误。
塔吉尔·瓦列夫2015年

15

forEach()方法对此流的每个元素执行一个操作。对于并行流,此操作不能保证维持流的顺序。

forEachOrdered() 方法针对此流的每个元素执行一个操作,以确保对具有定义的遇到顺序的流按遇到顺序处理每个元素。

请看下面的例子:

    String str = "sushil mittal";
    System.out.println("****forEach without using parallel****");
    str.chars().forEach(s -> System.out.print((char) s));
    System.out.println("\n****forEach with using parallel****");

    str.chars().parallel().forEach(s -> System.out.print((char) s));
    System.out.println("\n****forEachOrdered with using parallel****");

    str.chars().parallel().forEachOrdered(s -> System.out.print((char) s));

输出:

****forEach without using parallel****

sushil mittal

****forEach with using parallel****

mihul issltat

****forEachOrdered with using parallel****

sushil mittal
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.