Java 8 - Journey of for loop in Java, for(index) to forEach()

for loop has come a long way in Java 8 with a new forEach() method in class. In this article, we will take a look at the journey of for loop in different versions of Java programming language. for loop is there from the very beginning of Java i.e. JDK 1.0. Almost all Java programmers have used the classical for() loop, as it is also an essential programming construct, I guess just next to if-else, but when the foreach loop or as some people call it enhanced for loop was introduced in JDK 1.5, everything changed from looping over Collection and array perspective.

Yesterday's popular looping construct becomes old and ugly and more elegant solution took over. It was shorter, cleaner, and less error-prone, what else you need at that time.

Things were quiet in terms of for loop from the last 10 years, but  In Java 8, looping has taken another big step in its new avatar, forEach() method. It's not only short, clean but also take advantage of lazy evaluation and inbuilt parallelism of Java 8 Stream. let's revisit this journey of for loop in Java in this post of Javarevisited.

Btw, if you are not familiar with new Java 8 features like this one then I suggest you first go through a comprehensive and up-to-date Java course like The Complete Java MasterClass on Udemy. It's also very affordable and you can buy in just $10 on Udemy sales which happen every now and then.

Pre-JDK 1.5, this was my favorite way of iterating over an ArrayList or HashSet :

// pre JDK 1.5, printing each element of List using for loop
List<String> countries = Arrays.asList("India", "Australia", 
         "England", "South Africa");
for(int i=0; i < countries.size(); i++){

So when foreach loop or advanced for loop was added on Java 5, I quickly adapted to the following style of looping over Collection or List :

for(String country : countries){

This was much shorter, clearer, and less error-prone than the previous one and everybody loved it. You don't need to keep track of index, you don't need to call size() method in every step and it was less error-prone than the previous one, but it was still imperative. You are telling the compiler what to do and how to do like traditional for loop.

Things change drastically when the functional style of programming was introduced in Java 8 via lambda expression and new Stream API. Now you can loop over your collection without any loop in Java, you just need to use forEach() method of java.util.Stream class, as shown below : -> System.out.println(str));

This code has reduced looping over collection or list into just one line. To add into, If you want to perform some pre processing task e.g. filtering, conversion or mapping, you can also do this in the same line as shown below :
         .filter(country -> country.contains("n"))
         .forEach(str -> System.out.println(str));

This code will now only print "India" and "England" as it contains the letter "n". Java SE 8 for Really Impatient By Cay S. Horstmann  to learn more about filtering in Java 8.

This approach has several advantages over the previous two imperative approaches, first, it segregates what to do from how to do. You are just telling API to filter the list based upon condition you have given and then print those elements. Now API can print it by the way it wants, you don't need to worry about it.

The benefit is, you don't need to write imperative code, you will also benefit from lazy evaluation and any performance improvement done by API to accomplish your task. You can even make your code more concise using method reference feature of Java 8, as shown below :
         .filter(country -> country.contains("n"))

That "::" or scope resolution operator of C++ is used for method reference since you are not doing anything with String argument of println() then just passing it, you can use method reference there to make your code more clean and concise.

for loop changes in Java 1.4, 5 and 8

Here is the complete code example of using different for loops in Java world, including Java 8 forEach() method. This example demonstrates gradual changes made in for loop from Java 1.4, 5, and Java 8 versions.

package test;

import java.util.Arrays;
import java.util.List;

 * Java Program to demonstrate different ways to loop over collection in 
 * pre Java 8 and Java 8 world using Stream's forEach method.
 * @author Javin Paul
public class JourneyOfForLoopInJava {

    public static void main(String args[]) throws IOException {

        // pre JDK 1.5, printing each element of List using for loop
        List<String> countries = Arrays.asList("India", 
                     "Australia", "England", "South Africa");
        for(int i=0; i<countries.size(); i++){
        // In Java 5, we god advanced for loop, 
        // which makes it easy to loop over
        // List or Collection        
        for(String country : countries){
        // In Java 8, you can use forEach method of Stream class to loop over
        // any List or Collection -> System.out.println(str));
        // doing some pre-processing filtering on our list
    // will print India, England as only they contain "n"
                .filter(country -> country.contains("n"))
                .forEach(str -> System.out.println(str));
        // making the code more concise using method reference
                .filter(country -> country.contains("n"))


So you have seen, for loop has come a long way from JDK 1 to JDK 8, especially when you use with Collection. Gone are the days, when you need to worry about looping index, initializing it properly, making sure it ends properly to avoid IndexOutOfBoundsException and calling corresponding get() method on List.

Java 5 was the first step in making looping over Collection easy but Java 8 has provided a much powerful functional style looping in Java. In fact, it's not even a loop its just a method call, which means you can write high-performance Java Collection code without using a loop.

So next time, you need to loop over the collection, just don't use a simple or advanced for loop, considering using forEach() method of Stream. You will not only benefit from the modern way of filtering and mapping but also from lazy evaluation and performance improvement by smart looping implementation of API itself.

Further Learning
The Complete Java MasterClass
What's New in Java 8
Refactoring to Java 8 Streams and Lambdas Self- Study Workshop

Related Java 8 Tutorials
If you are interested in learning more about new features of Java 8,here are my earlier articles covering some of the important concepts of Java 8:
  • 20 Examples of Date and Time in Java 8 (tutorial)
  • How to use Stream class in Java 8 (tutorial)
  • How to use filter() method in Java 8 (tutorial)
  • How to use forEach() method in Java 8 (example)
  • How to join String in Java 8 (example)
  • How to convert List to Map in Java 8 (solution)
  • How to use peek() method in Java 8 (example)
  • 5 Books to Learn Java 8 from Scratch (books)
  • How to convert stream to array in Java 8 (tutorial)
  • Java 8 Certification FAQ (guide)
  • Java 8 Mock Exams and Practice Test (test)

Thanks for reading this article so far. If you like this article then please share with your friends and colleagues. If you have any question, doubt, or feedback then please drop a comment and I'll try to answer your question.

P.S. : Java 8 is bundle of many exciting features like this, if you are interested to learn more about them, you can pick any of the following books :
  • Java 8 in Action: Lambdas, Streams, and functional-style programming (see here)
  • Mastering Lambdas: Java Programming in a Multicore World (see here)


Anonymous said...

I thought generics were introduced with JDK 1.5. Wouldn't that made the "pre JDK 1.5" example wrong ?

javin paul said...

@Anonymous, well yes, generics was introduced in JDK 1.4 but the code was to demonstrate style of looping :)

Vladimir Dolzhenko said...

The most weird (and the worst) way to iterate over list with size and get - there are several pitfalls like if list is LinkedList - in this case complexity is O(n^2) instead of O(1) - or CopyOnWriteArrayList - one thread changing list while another thread iterates over it using size() / get() leads to that IndexOutOfBoundsException.

So - you made problems by your own using the bad practises as favorite.

The right approach (pre 1.4 and now days) is using Iterator:

for(final Iterator it = list.iterator(); it.hashNext(); ){
Object o =;

it is the best and the safetiest way to iterate over any collection w/o unpredictable bahaviour - moreover foreach loop is just syntax sugar over such construction.

javin paul said...

@Vladimir, Indeed Iterator is better way to iterate over List in Java 1.4, it not only hide the implementation detail like you said LinkedList doesn't support index based random search and could drastically affect performance, it provides a consistent way to loop through.

Vladimir Dolzhenko said...

@Javin - iterator is the only correct way available in java - java 1.1, 1.2, 1.3... and 1.7

As I said foreach loop is just a syntax sugar over iterator.

There is an alternative way to do the same in java 1.8 with stream api - BUT - that is completely another approach - the FP way - it does NOT mean iterator is not valid anymore - that's just second correct way.

YourDailyDude said...

How does foreach helps in lazy initialization and performance improvement?

javin paul said...

@nagaraju, forEach is stream based, which means implementation is free to evaluate result lazily, can decide to run the operation in parallel (e.g. printing, filtering etc) as well. That's why when you use forEach(), the order is not guaranteed.

Anonymous said...

@Javin I have a List with data like this
I need move some data where S_ID=142 to a new list and remove it from current list. How can I do it in java 8?

Achint Mittal said...

We can even directly use forEach() method from Iterable interface.

So, instead of using :: println);

we can write:

countries.forEach(System.out :: println);

But ofcourse in this approach, we are loosing lazy evaluation feature of streams.

Post a Comment