It looks like I can call list.forEach(a -> a.stuff())
directly on my collection, instead of list.stream().forEach(a -> a.stuff())
. When would I use one over the other (parallelStream()
aside..)?
1 Answers
There are a few differences:
Iterable.forEach
guarantees processing in iteration order, if it's defined for the Iterable. (Iteration order is generally well-defined for Lists.) Stream.forEach
does not; one must use Stream.forEachOrdered
instead.
Iterable.forEach
may permit side effects on the underlying data structure. Although many collections' iterators will throw ConcurrentModificationException
if the collection is modified during iteration, some collections' iterators explicitly permit it. See CopyOnWriteArrayList
, for example. By contrast, stream operations in general must not interfere with the stream source.
If the Iterable is a synchronized wrapper collection, for example, from Collections.synchronizedList()
, a call to forEach
on it will hold its lock during the entire iteration. This will prevent other threads from modifying the collection during the iteration, ensuring that the iteration sees a consistent view of the collection, and preventing ConcurrentModificationException
. (This will also prevent other threads from reading the collection during the iteration.) This is not the case for streams. There is nothing to prevent the collection from being modified during the stream operation, and if modification does occur, the result is undefined.

- 127,867
- 37
- 205
- 259
-
"preventing other threads from modifying it" — or reading from it either, surely? And your last point seems to imply that `Stream.forEach` contrasts with `Iterable.forEach` in allowing modification of the stream source. I doubt whether you meant to imply this! – Maurice Naftalin May 30 '14 at 16:17
-
I certainly didn't mean to imply that! I guess I should clarify that last bit. – Stuart Marks May 30 '14 at 17:45