Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between Java8 container `for each` and Stream `for each` [duplicate]

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.

like image 265
zzkyeee Avatar asked Jun 03 '18 02:06

zzkyeee


People also ask

What is the difference between stream and forEach in Java 8?

The subtle difference between Stream. forEach() and forEach() is: Java explicitly allows modifying elements using the iterator. Streams, in contrast, should be non-interfering.

What is difference between forEach and stream forEach?

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.

What is the difference between forEach and forEachOrdered?

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.

What is the difference between forEach and forEachRemaining?

forEach iterates through the elements of an Iterable . forEachRemaining iterates through the remaining elements of an Iterator .


1 Answers

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).

like image 177
Slaw Avatar answered Sep 22 '22 19:09

Slaw