A Guide to Iterator in Java

1. Introduction

An Iterator is one of many ways we can traverse a collection, and as every option, it has its pros and cons.

It was first introduced in Java 1.2 as a replacement of Enumerations and:

  • introduced improved method names
  • made it possible to remove elements from a collection we’re iterating over
  • doesn’t guarantee iteration order

In this tutorial, we’re going to review the simple Iterator interface to learn how we can use its different methods.

We’ll also check the more robust ListIterator extension which adds some interesting functionality.

2. The Iterator Interface

To start, we need to obtain an Iterator from a Collection; this is done by calling the iterator() method.

For simplicity, we’ll obtain Iterator instance from a list:

List<String> items = ...
Iterator<String> iter = items.iterator();

The Iterator interface has three core methods:

2.1. hasNext()

The hasNext() method can be used for checking if there’s at least one element left to iterate over.

It’s designed to be used as a condition in while loops:

while (iter.hasNext()) {
    // ...
}

2.2. next()

The next() method can be used for stepping over the next element and obtaining it:

String next = iter.next();

It’s good practice to use hasNext() before attempting to call next().

Iterators for Collections don’t guarantee iteration in any particular order unless particular implementation provides it.

2.3. remove()

Finally, if we want to remove the current element from the collection, we can use the remove:

iter.remove();

This is a safe way to remove elements while iterating over a collection without a risk of a ConcurrentModificationException.

2.4. Full Iterator Example

Now we can combine them all and have a look at how we use the three methods together for collection filtering:

while (iter.hasNext()) {
    String next = iter.next();
    System.out.println(next);
 
    if( "TWO".equals(next)) {
        iter.remove();				
    }
}

This is how we commonly use an Iterator, we check ahead of time if there is another element, we retrieve it and then we perform some action on it.

2.5. Iterating With Lambda Expressions

As we saw in the previous examples, it’s very verbose to use an Iterator when we just want to go over all the elements and do something with them.

Since Java 8, we have the forEachRemaining method that allows the use of lambdas to processing remaining elements:

iter.forEachRemaining(System.out::println);

3. The ListIterator Interface

ListIterator is an extension that adds new functionality for iterating over lists:

ListIterator<String> listIterator = items.listIterator(items.size());

Notice how we can provide a starting position which in this case is the end of the List.

3.1. hasPrevious() and previous()

ListIterator can be used for backward traversal so it provides equivalents of hasNext() and next():

while(listIterator.hasPrevious()) {
    String previous = listIterator.previous();
}

3.2. nextIndex() and previousIndex()

Additionally, we can traverse over indices and not actual elements:

String nextWithIndex = items.get(listIterator.nextIndex());
String previousWithIndex = items.get(listIterator.previousIndex());

This could prove very useful in case we need to know the indexes of the objects we’re currently modifying, or if we want to keep a record of removed elements.

3.3. add()

The add method, which, as the name suggests, allows us to add an element before the item that would be returned by next() and after the one returned by previous():

listIterator.add("FOUR");

3.4. set()

The last method worth mentioning is set(), which lets us replace the element that was returned in the call to next() or previous():

String next = listIterator.next();
if( "ONE".equals(next)) {
    listIterator.set("SWAPPED");
}

It’s important to note that this can only be executed if no prior calls to add() or remove() were made.

3.5. Full ListIterator Example

We can now combine them all to make a complete example:

ListIterator<String> listIterator = items.listIterator();
while(listIterator.hasNext()) {
    String nextWithIndex = items.get(listIterator.nextIndex());		
    String next = listIterator.next();
    if("REPLACE ME".equals(next)) {
        listIterator.set("REPLACED");
    }
}
listIterator.add("NEW");
while(listIterator.hasPrevious()) {
    String previousWithIndex
     = items.get(listIterator.previousIndex());
    String previous = listIterator.previous();
    System.out.println(previous);
}

In this example, we start by getting the ListIterator from the List, then we can obtain the next element either by index –which doesn’t increase the iterator’s internal current element – or by calling next.

Then we can replace a specific item with set and insert a new one with add.

After reaching the end of the iteration, we can go backward to modify additional elements or simply print them from bottom to top.

4. Conclusion

The Iterator interface allows us to modify a collection while traversing it, which is more difficult with a simple for/while statement. This, in turn, gives us a good pattern we can use in many methods that only requires collections processing while maintaining good cohesion and low coupling.

Finally, as always the full source code is available over at GitHub.

Related posts:

Assertions in JUnit 4 and JUnit 5
Java Program to Implement the Edmond’s Algorithm for Maximum Cardinality Matching
Java Program to Check if a Given Graph Contain Hamiltonian Cycle or Not
Tạo số và chuỗi ngẫu nhiên trong Java
Java Program to Compute Discrete Fourier Transform Using the Fast Fourier Transform Approach
Java Program to Implement Hash Tables Chaining with List Heads
Java Program to implement Circular Buffer
Reading an HTTP Response Body as a String in Java
Spring Data – CrudRepository save() Method
Java Program to Solve a Matching Problem for a Given Specific Case
Automatic Property Expansion with Spring Boot
Hướng dẫn Java Design Pattern – Mediator
Configure a RestTemplate with RestTemplateBuilder
Spring Boot - Hystrix
Java Program to Find k Numbers Closest to Median of S, Where S is a Set of n Numbers
Serialization và Deserialization trong java
Java Program to Perform Inorder Recursive Traversal of a Given Binary Tree
Java Program to Implement the Program Used in grep/egrep/fgrep
Debugging Reactive Streams in Java
Ép kiểu trong Java (Type casting)
Java Program to Perform the Unique Factorization of a Given Number
Java Program to Implement Sorted Circular Doubly Linked List
Java Program to Implement LinkedTransferQueue API
Java Program to Implement the Hungarian Algorithm for Bipartite Matching
Function trong Java 8
Introduction to Spring Security Expressions
Java Program to Implement K Way Merge Algorithm
Java Program to Perform Arithmetic Operations on Numbers of Size
Java Program to find the peak element of an array using Binary Search approach
Refactoring Design Pattern với tính năng mới trong Java 8
Setting a Request Timeout for a Spring REST API
Spring Boot Gradle Plugin