I know we can use List.foreach
to traverse,and we can use List.stream.foreach
to traverse too. I do not understand which is better to traverse in Java8.
The subtle difference between Stream. forEach() and forEach() is: Java explicitly allows modifying elements using the iterator. Streams, in contrast, should be non-interfering.
The reason for the different results is that forEach() used directly on the list uses the custom iterator, while stream(). forEach() simply takes elements one by one from the list, ignoring the iterator.
The difference between forEachOrdered() and forEach() methods is that forEachOrdered() will always perform given action in encounter order of elements in stream whereas forEach() method is non-deterministic.
forEach iterates through the elements of an Iterable . forEachRemaining iterates through the remaining elements of an Iterator .
The forEach(Consumer)
method is declared in the Iterable
interface which Collection
, and therefore List
, extends. The default implementation of forEach(Consumer)
is:
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
As you can see the default implementation simply calls the action
in a for-each loop. And a for-each loop is simply syntactic sugar for:
for (Iterator<?> iterator = iterable.iterator(); iterator.hasNext(); ) {
Object element = iterator.next();
// Do what you need to with element
}
Except you don't have access to the Iterator
in a for-each loop.
Specific implementations of Iterable
may change how it actually iterates its elements (it may or may not use an Iterator
) but it will almost always come down to some for
or while
loop. I say "almost always" because it's possible some type of recursion or chaining may be involved.
Now, using List.stream().forEach(Consumer)
creates an unnecessary Stream
object when you are simply trying to iterate the List
sequentially. You should only use the streaming API if you actually need to process a collection of elements in a pipeline fashion (such as mapping, filtering, mapping some more, etc...).
So, for simply iterating, using List.stream().forEach(Consumer)
is going to be less performant than a simple List.forEach(Consumer)
call in virtually all cases. The performance increase will most likely be negligible but it is an easy enough fix that the "optimization" is not excessive; especially if you don't make the "mistake" in the first place. Don't create objects if you don't need them.
It may be better to simply use a for-each loop instead of forEach(Consumer)
though. It can be easier to read than the more functional counterpart.
Edit
As mentioned in the comments by Holger, Stream.forEach(Consumer)
has a pretty major difference to Iterable.forEach(Consumer)
: It does not guarantee the encounter order of the elements. While the iteration order of Iterable.forEach(Consumer)
is not defined for the Iterable
interface either, it can be defined by extending interfaces (such as List
). When using a Stream
, however, the order is not guaranteed regardless of the source of the Stream
.
If you want the order to be guaranteed when using a Stream
you have to use Stream.forEachOrdered(Consumer)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With