Collection.stream().forEach() 和 Collection.forEach() 有什么区别? [英] What is difference between Collection.stream().forEach() and Collection.forEach()?

查看:35
本文介绍了Collection.stream().forEach() 和 Collection.forEach() 有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道使用 .stream(),我可以使用像 .filter() 这样的链式操作或使用并行流.但是如果我需要执行一些小的操作(例如打印列表的元素),它们之间有什么区别?

I understand that with .stream(), I can use chain operations like .filter() or use parallel stream. But what is difference between them if I need to execute small operations (for example, printing the elements of the list)?

collection.stream().forEach(System.out::println);
collection.forEach(System.out::println);

推荐答案

对于简单的情况,例如图示的情况,它们大体相同.但是,有许多细微的差异可能很重要.

For simple cases such as the one illustrated, they are mostly the same. However, there are a number of subtle differences that might be significant.

一个问题是订购.对于 Stream.forEach,顺序是未定义.顺序流不太可能发生这种情况,但它仍然在 Stream.forEach 以某种任意顺序执行的规范内.这在并行流中经常发生.相比之下,Iterable.forEach 总是按照 Iterable 的迭代顺序执行,如果指定了一个.

One issue is with ordering. With Stream.forEach, the order is undefined. It's unlikely to occur with sequential streams, still, it's within the specification for Stream.forEach to execute in some arbitrary order. This does occur frequently in parallel streams. By contrast, Iterable.forEach is always executed in the iteration order of the Iterable, if one is specified.

另一个问题是副作用.Stream.forEach 中指定的操作必须无干扰.(请参阅 java.util.流包 doc.) Iterable.forEach 可能有更少的限制.对于java.util 中的集合,Iterable.forEach 通常会使用该集合的Iterator,其中大部分被设计为fail-fast 并且会抛出 ConcurrentModificationException 如果集合在迭代期间在结构上被修改.但是,在迭代期间允许进行非结构性的修改.例如,ArrayList 类文档 说仅仅设置元素的值不是结构修改."因此,ArrayList.forEach 的操作可以毫无问题地在底层 ArrayList 中设置值.

Another issue is with side effects. The action specified in Stream.forEach is required to be non-interfering. (See the java.util.stream package doc.) Iterable.forEach potentially has fewer restrictions. For the collections in java.util, Iterable.forEach will generally use that collection's Iterator, most of which are designed to be fail-fast and which will throw ConcurrentModificationException if the collection is structurally modified during the iteration. However, modifications that aren't structural are allowed during iteration. For example, the ArrayList class documentation says "merely setting the value of an element is not a structural modification." Thus, the action for ArrayList.forEach is allowed to set values in the underlying ArrayList without problems.

并发集合再次不同.它们不是快速失败,而是被设计为 弱一致性.完整的定义在那个链接.简而言之,请考虑 ConcurrentLinkedDeque.传递给其 forEach 方法的操作可以修改底层双端队列,甚至在结构上,并且永远不会抛出 ConcurrentModificationException.但是,发生的修改在此迭代中可能可见,也可能不可见.(因此弱"一致性.)

The concurrent collections are yet again different. Instead of fail-fast, they are designed to be weakly consistent. The full definition is at that link. Briefly, though, consider ConcurrentLinkedDeque. The action passed to its forEach method is allowed to modify the underlying deque, even structurally, and ConcurrentModificationException is never thrown. However, the modification that occurs might or might not be visible in this iteration. (Hence the "weak" consistency.)

如果 Iterable.forEach 正在迭代同步集合,则还有另一个区别是可见的.在这样一个集合上,Iterable.forEach 获取集合的锁一次,并在对 action 方法的所有调用中保持它.Stream.forEach 调用使用集合的拆分器,它不锁定,并且依赖于不干扰的普遍规则.支持流的集合可以在迭代期间修改,如果是,则可能导致 ConcurrentModificationException 或不一致的行为.

Still another difference is visible if Iterable.forEach is iterating over a synchronized collection. On such a collection, Iterable.forEach takes the collection's lock once and holds it across all the calls to the action method. The Stream.forEach call uses the collection's spliterator, which does not lock, and which relies on the prevailing rule of non-interference. The collection backing the stream could be modified during iteration, and if it is, a ConcurrentModificationException or inconsistent behavior could result.

这篇关于Collection.stream().forEach() 和 Collection.forEach() 有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆