forEach vs forEachOrdered in Java 8 Stream

2022-08-31 10:15:24

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

例:

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

请举例说明2种方法产生不同产出的情况。


答案 1
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

引用自 forEach Javadoc:

此操作的行为是显式非确定性的。对于并行流管道,此操作不保证遵循流的遭遇顺序,因为这样做会牺牲并行性的好处。

forEachOrdered Javadoc 状态(强调我的):

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


答案 2

虽然更短,看起来更漂亮,但我建议在每个顺序重要的地方使用,以明确指定这一点。对于顺序流,似乎尊重顺序,甚至流API内部代码使用(对于已知是顺序的流),在语义上需要使用!但是,您以后可能会决定将流更改为并行,并且您的代码将被破坏。此外,当您使用代码的阅读器时,会看到以下消息:“此处的顺序很重要”。因此,它可以更好地记录您的代码。forEachforEachOrderedforEachforEachforEachOrderedforEachOrdered

另请注意,对于并行流,它不仅以非威慑性顺序执行,而且您还可以在不同元素的不同线程中同时执行它(这在 )。forEachforEachOrdered

最后,两者都很少有用。在大多数情况下,您实际上需要产生一些结果,而不仅仅是副作用,因此像或应该这样的操作更合适。通过表达自然还原操作通常被认为是一种不好的风格。forEachforEachOrderedreducecollectforEach