Ways to Iterate Over a List in Java

1. Introduction

Iterating over the elements of a list is one of the most common tasks in a program.

In this tutorial, we’re going to review different ways to do this in Java. We’ll be focusing on iterating through the list in order, though going in reverse is simple, too.

2. for Loop

Firstly, let’s review some for loop options.

Let’s begin by defining a list of countries for our examples:

List<String> countries = Arrays.asList("Germany", "Panama", "Australia");

2.1. Basic for Loop

The most common flow control statement for iteration is the basic for loop.

The for loop defines three types of statements separated with semicolons. The first statement is the initialization statement. The second one defines the termination condition. The last statement is the update clause.

Here, we’re simply using an integer variable as an index:

for (int i = 0; i < countries.size(); i++) {
    System.out.println(countries.get(i));
}

In the initialization, we must declare an integer variable to specify the starting point. This variable typically acts as the list index.

The termination condition is an expression that after evaluation returns a boolean, once this expression evaluates to false the loop finishes.

The update clause is used to modify the current state of the index variable, increasing it or decreasing it until the point of termination.

2.2. Enhanced for Loop

The enhanced for loop is a simple structure that allows us to visit every element of a list. It is similar to the basic for loop but more readable and compact. Consequently, is one of the most commonly used forms to traverse a list.

Notice that the enhanced for loop is simpler than the basic for loop:

for (String country : countries) {
    System.out.println(country); 
}

3. Iterators

An Iterator is a design pattern that offers us a standard interface to traverse a data structure without having to worry about the internal representation.

This way of traversing data structures offers many advantages, among which we can emphasize that our code does not depend on the implementation.

Therefore, the structure can be a binary tree or a doubly linked list since the Iterator abstracts us from the way of performing the traversal. In this way, we can easily replace data structures in our code without unpleasant problems.

3.1. Iterator

In Java, the Iterator pattern is reflected in the java.util.Iterator class. It is widely used in Java Collections. There are two key methods in an Iterator, the hasNext() and next() methods.

Here, we demonstrate the usage of both:

Iterator<String> countriesIterator = countries.iterator();

while(countriesIterator.hasNext()) {
    System.out.println(countriesIterator.next()); 
}

The hasNext() method checks if there are any elements remaining in the list.

The next() method returns the next element in the iteration.

3.2. ListIterator

ListIterator allows us to traverse a list of elements in either forward or backward order.

Scrolling a list with ListIterator forward follows a mechanism similar to that used by the Iterator. In this way, we can move the iterator forward with the next() method, and we can find the end of the list using the hasNext() method.

As we can see, the ListIterator looks very similar to the Iterator that we used previously:

ListIterator<String> listIterator = countries.listIterator();

while(listIterator.hasNext()) {
    System.out.println(listIterator.next());
}

4. forEach()

4.1. Iterable.forEach()

Since Java 8, we can use the forEach() method to iterate over the elements of a list.  This method is defined in the Iterable interface and can accept Lambda expressions as a parameter.

The syntax is pretty simple:

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

Before the forEach function, all iterators in Java were active, that is, they involved a for or a while loop that traversed the data collection until a certain condition was met.

With the introduction of forEach as a function in the Iterable interface, all classes that implement Iterable have the forEach function added.

4.2. Stream.forEach()

We can also convert a collection of values to a Stream and we can have access to operations such as forEach()map(), or filter().

Here, we demonstrate a typical usage for streams:

countries.stream().forEach((c) -> System.out.println(c));

5. Conclusion

In this article, we showed the different ways to iterate over the elements of a list using the Java API. Among these, we mentioned the for loop, the enhanced for loop, the Iterator, the ListIterator and the forEach() method (included in Java 8).

In addition, we also showed how to use the forEach() method with Streams.

Finally, all the code used in this article is available in our Github repo.