我知道这些方法的执行顺序不同,但在所有测试中,我都无法实现不同的执行顺序。
例子:
1 2 3 4
| 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 )); |
输出:
1 2 3 4 5 6 7 8
| forEach Demo
Output:AAA
Output:BBB
Output:CCC
forEachOrdered Demo
Output:AAA
Output:BBB
Output:CCC |
请提供两种方法产生不同输出的示例。
- 试着用平行的溪流。
- @是唯一可能的选择吗?
- 未指明的订单并不意味着"保证是不同的订单"。它只是表示未指定,这总是意味着有可能匹配遭遇顺序。没有内置的无序播放功能。
1 2
| 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 )); |
第二行将始终输出
1 2 3
| Output:AAA
Output:BBB
Output:CCC |
而第一个是不保证的,因为订单没有保存。forEachOrdered将按流源指定的顺序处理流元素,而不管流是顺序的还是并行的。
引用forEachjavadoc:
The behavior of this operation is explicitly nondeterministic. For parallel stream pipelines, this operation does not guarantee to respect the encounter order of the stream, as doing so would sacrifice the benefit of parallelism.
当forEachOrderedjavadoc声明(强调mine)时:
Performs an action for each element of this stream, in the encounter order of the stream if the stream has a defined encounter order.
- 是的,你是对的。只有并行流才有可能吗?
- 即使它现在只适用于并行流——我不是说它适用于并行流——如果一些中间步骤得到优化以利用无序流,那么将来它仍然可能会中断,例如,如果流无序,排序可能会使用不稳定的算法。
- 所以把forEachOrdered和parallel一起使用是没有意义的?
- @是的,没错。stackoverflow.com/questions/47336825/…
- 使用foreachored将按顺序处理元素,然后使用并行流将失去并行的好处。请建议。
虽然forEach较短,看起来更漂亮,但我建议在所有需要订单明确说明的地方使用forEachOrdered。对于顺序流,forEach似乎尊重顺序,甚至流API内部代码也使用forEach(对于已知为顺序流的流),在语义上需要使用forEachOrdered!然而,您可能稍后决定将流更改为并行,您的代码将被破坏。同样,当您使用forEachOrdered时,代码的阅读器会看到消息:"订单在这里很重要"。因此,它更好地记录了您的代码。
还要注意,对于并行流,forEach不仅以非确定顺序执行,而且还可以在不同线程中针对不同元素同时执行(这在forEachOrdered中是不可能的)。
最后,两个forEach和forEachOrdered都很少有用。在大多数情况下,您实际上需要产生一些结果,而不仅仅是副作用,因此像reduce或collect这样的操作应该更合适。通过forEach表达自然还原操作通常被认为是一种不好的方式。
- "最后,两个前臂/前臂合唱很少有用"。我不能再同意了。这些方法似乎用得太多了。
- 谢谢你的回答。但这不是现实生活中的例子。我刚学了Java 8
- 为什么在该代码中使用forEachOrdered在语义上是必要的?
- @Real怀疑论,它是用户指定的流(传递到flatMap中)。它可以是有序的,因此必须以相同的顺序放入生成的流中。
- 为什么?在flatMap的合同中,你看到它说它将按相同的顺序放入输出中吗?
- @真正的怀疑论者,你才是真正的怀疑论者!Stream.of("a","b","c").flatMap(s -> Stream.of("1","2","3").map(s::concat)).spliterator().hasCharacteristics(Spliterator.ORDERED)返回true,因此必须确定生成流的顺序。如果您觉得JDK文档应该明确地说明这一点,那么可以提交一个bug。
- "foreach很少有用"…至于填充一个集合,我可以理解你的观点——但list.addAll(stream.collect(toList))不是占用了stream.forEach(list::add)两倍的内存吗?但是stream.forEach(this::doSomethingTotallyUnrelatedToFillingAList)呢?
- 我强烈反对江户十一〔九〕很少使用。当您需要处理大量数据集合时,很明显您将并行完成任务。在那里提交lambda函数非常有用。当我确实需要对结果进行排序时,我将它与IntStream一起使用;处理方法接收输入集合,输出将与来自该流的int一起收集,后者是两个集合的索引。这样,就不必使用线程安全的数据收集,这样可以使代码运行得更快,而且由于同步收集,所以顺序仍然保持不变。
for each()方法为该流的每个元素执行一个操作。对于并行流,此操作不保证维持流的顺序。
foreachored()方法对该流中的每个元素执行一个操作,确保对具有定义的遇到顺序的流按遇到顺序处理每个元素。
举个例子:
1 2 3 4 5 6 7 8 9 10 11
| String str ="sushil mittal";
System. out. println("****forEach without using parallel****");
str. chars(). forEach(s -> System. out. print((char) s ));
System. out. println("
****forEach with using parallel****");
str. chars(). parallel(). forEach(s -> System. out. print((char) s ));
System. out. println("
****forEachOrdered with using parallel****");
str. chars(). parallel(). forEachOrdered(s -> System. out. print((char) s )); |
输出:
****不使用parallel的foreach***
苏希米塔尔
****使用parallel的foreach***
米胡尔伊斯斯塔特
****使用parallel进行foreachored***
苏希米塔尔