The better practice is to use for-each. Besides violating the Keep It Simple, Stupid principle, the new-fangled forEach() has at least the following deficiencies:

  • Can't use non-final variables. So, code like the following can't be turned into a forEach lambda:
Object prev = null;
for(Object curr : list)
{
    if( prev != null )
        foo(prev, curr);
    prev = curr;
}
  • Can't handle checked exceptions. Lambdas aren't actually forbidden from throwing checked exceptions, but common functional interfaces like Consumer don't declare any. Therefore, any code that throws checked exceptions must wrap them in try-catch or Throwables.propagate(). But even if you do that, it's not always clear what happens to the thrown exception. It could get swallowed somewhere in the guts of forEach()

  • Limited flow-control. A return in a lambda equals a continue in a for-each, but there is no equivalent to a break. It's also difficult to do things like return values, short circuit, or set flags (which would have alleviated things a bit, if it wasn't a violation of the no non-final variables rule). "This is not just an optimization, but critical when you consider that some sequences (like reading the lines in a file) may have side-effects, or you may have an infinite sequence."

  • Might execute in parallel, which is a horrible, horrible thing for all but the 0.1% of your code that needs to be optimized. Any parallel code has to be thought through (even if it doesn't use locks, volatiles, and other particularly nasty aspects of traditional multi-threaded execution). Any bug will be tough to find.

  • Might hurt performance, because the JIT can't optimize forEach()+lambda to the same extent as plain loops, especially now that lambdas are new. By "optimization" I do not mean the overhead of calling lambdas (which is small), but to the sophisticated analysis and transformation that the modern JIT compiler performs on running code.

  • If you do need parallelism, it is probably much faster and not much more difficult to use an ExecutorService. Streams are both automagical (read: don't know much about your problem) and use a specialized (read: inefficient for the general case) parallelization strategy (fork-join recursive decomposition).

  • Makes debugging more confusing, because of the nested call hierarchy and, god forbid, parallel execution. The debugger may have issues displaying variables from the surrounding code, and things like step-through may not work as expected.

  • Streams in general are more difficult to code, read, and debug. Actually, this is true of complex "fluent" APIs in general. The combination of complex single statements, heavy use of generics, and lack of intermediate variables conspire to produce confusing error messages and frustrate debugging. Instead of "this method doesn't have an overload for type X" you get an error message closer to "somewhere you messed up the types, but we don't know where or how." Similarly, you can't step through and examine things in a debugger as easily as when the code is broken into multiple statements, and intermediate values are saved to variables. Finally, reading the code and understanding the types and behavior at each stage of execution may be non-trivial.

  • Sticks out like a sore thumb. The Java language already has the for-each statement. Why replace it with a function call? Why encourage hiding side-effects somewhere in expressions? Why encourage unwieldy one-liners? Mixing regular for-each and new forEach willy-nilly is bad style. Code should speak in idioms (patterns that are quick to comprehend due to their repetition), and the fewer idioms are used the clearer the code is and less time is spent deciding which idiom to use (a big time-drain for perfectionists like myself!).

As you can see, I'm not a big fan of the forEach() except in cases when it makes sense.

Particularly offensive to me is the fact that Stream does not implement Iterable (despite actually having method iterator) and cannot be used in a for-each, only with a forEach(). I recommend casting Streams into Iterables with (Iterable<T>)stream::iterator. A better alternative is to use StreamEx which fixes a number of Stream API problems, including implementing Iterable.

That said, forEach() is useful for the following:

  • Atomically iterating over a synchronized list. Prior to this, a list generated with Collections.synchronizedList() was atomic with respect to things like get or set, but was not thread-safe when iterating.

  • Parallel execution (using an appropriate parallel stream). This saves you a few lines of code vs using an ExecutorService, if your problem matches the performance assumptions built into Streams and Spliterators.

  • Specific containers which, like the synchronized list, benefit from being in control of iteration (although this is largely theoretical unless people can bring up more examples)

  • Calling a single function more cleanly by using forEach() and a method reference argument (ie, list.forEach (obj::someMethod)). However, keep in mind the points on checked exceptions, more difficult debugging, and reducing the number of idioms you use when writing code.

Articles I used for reference:

  • Everything about Java 8
  • Iteration Inside and Out (as pointed out by another poster)

EDIT: Looks like some of the original proposals for lambdas (such as http://www.javac.info/closures-v06a.html Google Cache) solved some of the issues I mentioned (while adding their own complications, of course).

Answer from Aleksandr Dubinsky on Stack Overflow
๐ŸŒ
W3Schools
w3schools.com โ€บ java โ€บ java_foreach_loop.asp
Java For-Each Loop
HTML Reference CSS Reference JavaScript Reference SQL Reference Python Reference W3.CSS Reference Bootstrap Reference PHP Reference HTML Colors Java Reference AngularJS Reference jQuery Reference ยท HTML Examples CSS Examples JavaScript Examples How To Examples SQL Examples Python Examples W3.CSS Examples Bootstrap Examples PHP Examples Java Examples XML Examples jQuery Examples
๐ŸŒ
Baeldung
baeldung.com โ€บ home โ€บ java โ€บ core java โ€บ guide to the java foreach loop
Guide to the Java forEach Loop | Baeldung
June 17, 2025 - In this tutorial, weโ€™ll see how to use the forEach() method with collections, what kind of argument it takes, and how this loop differs from the enhanced for-loop. If you need to brush up on some Java 8 concepts, check out our collection of articles.
๐ŸŒ
HowToDoInJava
howtodoinjava.com โ€บ home โ€บ java 8 โ€บ java foreach()
Java forEach() with Examples - HowToDoInJava
February 6, 2023 - List<Integer> numberList = List.of(1,2,3,4,5); Consumer<Integer> action = System.out::println; numberList.stream() .filter(n -> n%2 != 0) .parallel() .forEachOrdered( action ); Program output.
๐ŸŒ
Codecademy
codecademy.com โ€บ docs โ€บ java โ€บ arraylist โ€บ .foreach()
Java | ArrayList | .forEach() | Codecademy
April 13, 2025 - The .forEach() method does not return any value. This example demonstrates how to print all elements in an ArrayList using the .forEach() method with a lambda expression:
๐ŸŒ
Oracle
docs.oracle.com โ€บ javase โ€บ 8 โ€บ docs โ€บ technotes โ€บ guides โ€บ language โ€บ foreach.html
The For-Each Loop
2 weeks ago - The iterator is just clutter. Furthermore, it is an opportunity for error. The iterator variable occurs three times in each loop: that is two chances to get it wrong. The for-each construct gets rid of the clutter and the opportunity for error. Here is how the example looks with the for-each ...
๐ŸŒ
GeeksforGeeks
geeksforgeeks.org โ€บ java โ€บ arraylist-foreach-method-in-java
ArrayList forEach() Method in Java - GeeksforGeeks
July 11, 2025 - Example 2: Here, we will use the forEach() method with a lambda expression to print the square of each element in an ArrayList of Integers. Java ยท
Top answer
1 of 8
653

The better practice is to use for-each. Besides violating the Keep It Simple, Stupid principle, the new-fangled forEach() has at least the following deficiencies:

  • Can't use non-final variables. So, code like the following can't be turned into a forEach lambda:
Object prev = null;
for(Object curr : list)
{
    if( prev != null )
        foo(prev, curr);
    prev = curr;
}
  • Can't handle checked exceptions. Lambdas aren't actually forbidden from throwing checked exceptions, but common functional interfaces like Consumer don't declare any. Therefore, any code that throws checked exceptions must wrap them in try-catch or Throwables.propagate(). But even if you do that, it's not always clear what happens to the thrown exception. It could get swallowed somewhere in the guts of forEach()

  • Limited flow-control. A return in a lambda equals a continue in a for-each, but there is no equivalent to a break. It's also difficult to do things like return values, short circuit, or set flags (which would have alleviated things a bit, if it wasn't a violation of the no non-final variables rule). "This is not just an optimization, but critical when you consider that some sequences (like reading the lines in a file) may have side-effects, or you may have an infinite sequence."

  • Might execute in parallel, which is a horrible, horrible thing for all but the 0.1% of your code that needs to be optimized. Any parallel code has to be thought through (even if it doesn't use locks, volatiles, and other particularly nasty aspects of traditional multi-threaded execution). Any bug will be tough to find.

  • Might hurt performance, because the JIT can't optimize forEach()+lambda to the same extent as plain loops, especially now that lambdas are new. By "optimization" I do not mean the overhead of calling lambdas (which is small), but to the sophisticated analysis and transformation that the modern JIT compiler performs on running code.

  • If you do need parallelism, it is probably much faster and not much more difficult to use an ExecutorService. Streams are both automagical (read: don't know much about your problem) and use a specialized (read: inefficient for the general case) parallelization strategy (fork-join recursive decomposition).

  • Makes debugging more confusing, because of the nested call hierarchy and, god forbid, parallel execution. The debugger may have issues displaying variables from the surrounding code, and things like step-through may not work as expected.

  • Streams in general are more difficult to code, read, and debug. Actually, this is true of complex "fluent" APIs in general. The combination of complex single statements, heavy use of generics, and lack of intermediate variables conspire to produce confusing error messages and frustrate debugging. Instead of "this method doesn't have an overload for type X" you get an error message closer to "somewhere you messed up the types, but we don't know where or how." Similarly, you can't step through and examine things in a debugger as easily as when the code is broken into multiple statements, and intermediate values are saved to variables. Finally, reading the code and understanding the types and behavior at each stage of execution may be non-trivial.

  • Sticks out like a sore thumb. The Java language already has the for-each statement. Why replace it with a function call? Why encourage hiding side-effects somewhere in expressions? Why encourage unwieldy one-liners? Mixing regular for-each and new forEach willy-nilly is bad style. Code should speak in idioms (patterns that are quick to comprehend due to their repetition), and the fewer idioms are used the clearer the code is and less time is spent deciding which idiom to use (a big time-drain for perfectionists like myself!).

As you can see, I'm not a big fan of the forEach() except in cases when it makes sense.

Particularly offensive to me is the fact that Stream does not implement Iterable (despite actually having method iterator) and cannot be used in a for-each, only with a forEach(). I recommend casting Streams into Iterables with (Iterable<T>)stream::iterator. A better alternative is to use StreamEx which fixes a number of Stream API problems, including implementing Iterable.

That said, forEach() is useful for the following:

  • Atomically iterating over a synchronized list. Prior to this, a list generated with Collections.synchronizedList() was atomic with respect to things like get or set, but was not thread-safe when iterating.

  • Parallel execution (using an appropriate parallel stream). This saves you a few lines of code vs using an ExecutorService, if your problem matches the performance assumptions built into Streams and Spliterators.

  • Specific containers which, like the synchronized list, benefit from being in control of iteration (although this is largely theoretical unless people can bring up more examples)

  • Calling a single function more cleanly by using forEach() and a method reference argument (ie, list.forEach (obj::someMethod)). However, keep in mind the points on checked exceptions, more difficult debugging, and reducing the number of idioms you use when writing code.

Articles I used for reference:

  • Everything about Java 8
  • Iteration Inside and Out (as pointed out by another poster)

EDIT: Looks like some of the original proposals for lambdas (such as http://www.javac.info/closures-v06a.html Google Cache) solved some of the issues I mentioned (while adding their own complications, of course).

2 of 8
174

The advantage comes into account when the operations can be executed in parallel. (See http://java.dzone.com/articles/devoxx-2012-java-8-lambda-and - the section about internal and external iteration)

  • The main advantage from my point of view is that the implementation of what is to be done within the loop can be defined without having to decide if it will be executed in parallel or sequential

  • If you want your loop to be executed in parallel you could simply write

     joins.parallelStream().forEach(join -> mIrc.join(mSession, join));
    

    You will have to write some extra code for thread handling etc.

Note: For my answer I assumed joins implementing the java.util.Stream interface. If joins implements only the java.util.Iterable interface this is no longer true.

๐ŸŒ
GeeksforGeeks
geeksforgeeks.org โ€บ java โ€บ for-each-loop-in-java
For-Each Loop in Java - GeeksforGeeks
3 weeks ago - Example 2: Iterating in a List using for-each loop ... import java.util.*; class Geeks { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(3); list.add(5); list.add(7); list.add(9); int max = Integer.MIN_VALUE; for (int num : list) { if (num > max) { max = num; } } System.out.println("List of Integers: " + list); System.out.println("Maximum element: " + max); } }
Find elsewhere
๐ŸŒ
Mkyong
mkyong.com โ€บ home โ€บ java8 โ€บ java 8 foreach examples
Java 8 forEach examples - Mkyong.com
December 4, 2020 - Great examples. Thanks. ... It really helped me.. thank you so much ... Thanks, I was iterating a forEeah loop and instead of sysout. I want to perform few operations but I was getting an error. Your post help me identify what should I do. ... hello, thanks for this tutorial. In Java 8 possible to use โ€˜::โ€™ ? items.forEach(System.out::println);
๐ŸŒ
W3Schools
w3schools.com โ€บ java โ€บ ref_arraylist_foreach.asp
Java ArrayList forEach() Method
Java Examples Java Videos Java ... numbers.add(5); numbers.add(9); numbers.add(8); numbers.add(1); numbers.forEach( (n) -> { System.out.println(n); } ); } } Try it Yourself ยป ยท...
๐ŸŒ
Tutorialspoint
tutorialspoint.com โ€บ java โ€บ java_foreach_loop.htm
Java - for each Loop
In this example, we're showing the use of a foreach loop to print contents of an List of Integers. Here we're creating an List of integers as numbers and initialized it some values.
๐ŸŒ
Medium
rameshfadatare.medium.com โ€บ java-stream-foreach-examples-8696ed4af274
Java Stream forEach() Examples - Ramesh Fadatare
September 27, 2024 - Hereโ€™s an example where we use ... such as calculating and printing the length of each string: import java.util.stream.Stream; public class ForEachComplexExample { public static void main(String[] args) { Stream<String> stream = Stream.of("apple", "banana", "cherry"); // Use forEach() to print the length of each element stream.forEach(s -> System.out.println(s + " has length " + s.length())); } ...
๐ŸŒ
Medium
neesri.medium.com โ€บ master-in-java-8-foreach-48ac3fc940dc
Master in the forEach() Method in Java 8 | by A cup of JAVA coffee with NeeSri | Medium
August 3, 2024 - Using curly braces within the forEach method in Java 8 allows you to include multiple statements or more complex logic within the lambda expression. Here is the previous example refactored to use curly braces:
๐ŸŒ
Java67
java67.com โ€บ 2016 โ€บ 01 โ€บ how-to-use-foreach-method-in-java-8-examples.html
10 Examples of forEach() method in Java 8 | Java67
You can read more about that in the Collections to Streams in Java 8 Using the Lambda Expressions course on Pluralsight, which provides an in-depth explanation of new Java 8 features. So far you have both basic and advanced examples of using the forEach() method, first with simply iterating over each element and then along with using the filter() method, Let's see one more example of the forEach() method along with the map() function, which is another key functionality of Stream API.
๐ŸŒ
Javatpoint
javatpoint.com โ€บ java-8-foreach
Java 8 forEach() Method
Java 8 forEach Tutorial with examples and topics on functional interface, anonymous class, lambda for list, lambda for comparable, default methods, method reference, java date and time, java nashorn, java optional, stream, filter etc.
๐ŸŒ
ZetCode
zetcode.com โ€บ java โ€บ foreach
Java forEach - forEach on Java lists, maps, sets
June 17, 2025 - In this example, we illustrate how to iterate over a list of strings using the forEach method. Here, we implement the Consumer interface explicitly to print each element. This verbose approach can be streamlined using Java's lambda expressions, as shown later.
๐ŸŒ
CodeAhoy
codeahoy.com โ€บ java โ€บ foreach-in-java
Complete Guide to Java 8 forEach | CodeAhoy
February 19, 2021 - A complete guide to forEach method() and for-each loop in Java with lots of examples.
๐ŸŒ
BeginnersBook
beginnersbook.com โ€บ 2017 โ€บ 10 โ€บ java-8-foreach
Java 8 forEach method with example
Lets take an example to understand the difference between forEach() and forEachOrdered(). import java.util.List; import java.util.ArrayList; public class Example { public static void main(String[] args) { List<String> names = new ArrayList<String>(); names.add("Maggie"); names.add("Michonne"); names.add("Rick"); names.add("Merle"); names.add("Governor"); //forEach - the output would be in any order System.out.println("Print using forEach"); names.stream() .filter(f->f.startsWith("M")) .parallel() .forEach(n->System.out.println(n)); /* forEachOrdered - the output would always be in this order: * Maggie, Michonne, Merle */ System.out.println("Print using forEachOrdered"); names.stream() .filter(f->f.startsWith("M")) .parallel() .forEachOrdered(n->System.out.println(n)); } }
๐ŸŒ
Blogger
javarevisited.blogspot.com โ€บ 2015 โ€บ 09 โ€บ java-8-foreach-loop-example.html
Java 8 forEach() Loop Example
You can write more code by following above techniques, I suggest you experiment with different stream methods to learn more. Here is my sample program to demonstrate how to use forEach() statement to iterate over every element of a list, set or stream in Java.
๐ŸŒ
Vultr
docs.vultr.com โ€บ java โ€บ standard-library โ€บ java โ€บ util โ€บ ArrayList โ€บ forEach
Java ArrayList forEach() - Apply Action To Each Item | Vultr Docs
September 27, 2024 - class Printer { public void print(String message) { System.out.println("Message: " + message); } } List<String> messages = Arrays.asList("Hello", "World", "Java"); Printer printer = new Printer(); messages.forEach(printer::print); Explain Code ยท In this example, each string in messages is passed to the print method of the Printer class instance, highlighting how method references can link to instance methods.