Java iterators are essential in managing and accessing lists efficiently, acting as a standard mechanism for discovery through data structures. Whether you are new to Java programming or a senior developer, understanding iterators is necessary for working with collections in a structured and optimized way. This article delves into Java iterators, exploring their features, use cases, implementation details, and best practices.
What is an Iterator in Java?
An iterator design pattern allows sequential access to collection elements without revealing the underlying structure. The underlying structure of the collection. In Java, iterators are part of the java.util package and are primarily used with collection classes like ArrayList, LinkedList, HashSet, and others.
The Iterator interface defines methods for traversing collections, ensuring developers can iterate over a collection without understanding its implementation details.
Key Features of Java Iterators
- Universal Traversal Interface
Iterators allow a standard way to traverse different collection types, ensuring consistency and simplicity. - Fail-Fast Mechanism
Iterators in Java are fail-fast, meaning they throw aConcurrentModificationExceptionif a collection is structurally modified after the iterator is created, guaranteeing safe iteration. - Lightweight and Easy to Implement
Compared to other traversal mechanisms, iterators are lightweight and easy to implement, making them ideal for general-purpose iteration.
Core Methods of the Iterator Interface
The Iterator interface provides three primary methods:
boolean hasNext()
Determines whether there are more elements in the collection to iterate over.
while(iterator.hasNext()) {
System.out.println(iterator.next());
}2. E next()
Returns the next element in the collection. If there are no more elements, it throws a NoSuchElementException.
3. void remove()
Removes the last element returned by the iterator. This method can only be called once per call to next(), and it throws an UnsupportedOperationException if the collection does not support the remove operation.
How to Use Java Iterators
Here’s a basic example illustrating how to use an iterator:
import java.util.ArrayList;
import java.util.Iterator;
public class IteratorExample {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Cherry");
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}Apple Banana Cherry
Advantages of Iterators
- Abstraction
Iterators abstract the details of traversing a collection, making the code cleaner and easier to maintain. - Flexibility
They support multiple collection types, providing a uniform interface for traversal. - Fail-Fast Behavior
By detecting concurrent modifications, iterators help prevent subtle bugs and maintain data integrity. - Safe Removal
Iterators enable the safe removal of elements during traversal, something that’s challenging with traditional loops.
Iterator vs. Enhanced For-Loop
The enhanced for-loop is a syntactic sugar over iterators but lacks certain capabilities:

While the enhanced for-loop is concise and suitable for most cases, iterators are indispensable when element removal or fine-grained control over traversal is required.
Best Practices with Iterators
- Avoid Concurrent Modifications
Use iterators when you need to traverse and modify a collection concurrently to avoidConcurrentModificationException. - Prefer Enhanced For-Loop When Possible
Use enhanced for-loops for simple traversals without requiring removal or custom logic. - Use
ListIteratorfor Bi-Directional Traversal
If you need to traverse a list both forward and backward, consider usingListIterator. - Check for
hasNext()Before Callingnext()
Always ensure thathasNext()returns true before invokingnext()to avoid runtime exceptions.
Iterator Implementations
- Default Iterator
Every collection in Java provides an iterator implementation, allowing you to useiterator()to get an instance. - Custom Iterator
You can implement your iterator by adhering to theIteratorinterface. This is useful for custom data structures.
import java.util.Iterator;
public class CustomCollection implements Iterable<String> {
private String[] items = {"One", "Two", "Three"};
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
private int index = 0;
@Override
public boolean hasNext() {
return index < items.length;
}
@Override
public String next() {
return items[index++];
}
};
}
}ListIterator: Extending the Iterator Interface
The ListIterator interface extends Iterator, adding support for bi-directional traversal and modification. Key methods include:
boolean hasPrevious(): Checks if there are elements before the current position.E previous(): Returns the previous element.void add(E e): Inserts an element at the current position.
Example:
import java.util.ArrayList;
import java.util.ListIterator;
public class ListIteratorExample {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
ListIterator<String> listIterator = list.listIterator();
while (listIterator.hasNext()) {
System.out.println("Next: " + listIterator.next());
}
while (listIterator.hasPrevious()) {
System.out.println("Previous: " + listIterator.previous());
}
}
}Next: A Next: B Next: C Previous: C Previous: B Previous: A
Limitations of Iterators
- One-Directional
Basic iterators can only traverse forward; useListIteratorfor bidirectional navigation. - Single-Use
An iterator can only traverse a collection once. To traverse again, a new iterator must be created. - Lacks Random Access
Iterators are sequential; accessing elements randomly is inefficient compared to indexed access in lists.
Common Mistakes When Using Iterators in Java
Iterators are potent tools for traversing collections in Java, but they can be prone to misuse or misunderstanding, especially for beginners. Here are the most common mistakes when using iterators and how to avoid them:
1. Ignoring the hasNext() Check
Mistake:
Calling next() without first checking hasNext() can lead to a NoSuchElementException.
Example:
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
Iterator<String> iterator = list.iterator();
System.out.println(iterator.next());
System.out.println(iterator.next());
System.out.println(iterator.next()); // Throws NoSuchElementException
}A B Exception in thread "main" java.util.NoSuchElementException at java.base/java.util.ArrayList$Itr.next(ArrayList.java:1052) at com.example.programming.utils.IteratorExample.main(IteratorExample.java:16)
Solution:
Always check hasNext() before calling next().
Corrected Code:
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}2. Attempting to Use remove() Before next()
Mistake:
Calling remove() without first calling next() results in an IllegalStateException.
Example:
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
Iterator<String> iterator = list.iterator();
iterator.remove(); // Throws IllegalStateException
}Exception in thread "main" java.lang.IllegalStateException at java.base/java.util.ArrayList$Itr.remove(ArrayList.java:1062) at com.example.programming.utils.IteratorExample.main(IteratorExample.java:14)
Why It Happens:
The remove() method relies on next() to identify the element to be removed.
Solution:
Always call next() before using remove().
Corrected Code:
Iterator<String> iterator = list.iterator();
if (iterator.hasNext()) {
iterator.next();
iterator.remove(); // Safe
}3. Using remove() in Unsupported Collections
Mistake:
Not all iterators support the remove() method. For instance, iterators of immutable collections or arrays do not allow removal.
Example:
public static void main(String[] args) {
List<String> unmodifiableList = List.of("A", "B", "C");
Iterator<String> iterator = unmodifiableList.iterator();
iterator.remove(); // Throws UnsupportedOperationException
}Exception in thread "main" java.lang.UnsupportedOperationException at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:142) at java.base/java.util.ImmutableCollections$ListItr.remove(ImmutableCollections.java:387) at com.example.programming.utils.IteratorExample.main(IteratorExample.java:12)
Solution:
Check the documentation of the collection. Avoid calling remove() if the collection is immutable.
4. Not Reinitializing Iterators for Re-Traversal
Mistake:
Attempting to reuse an iterator after completing a traversal.
Example:
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
while (iterator.hasNext()) {
System.out.println(iterator.next()); // Won't execute
}Solution:
Create a new iterator for subsequent traversals.
Corrected Code:
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// Create a new iterator
iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}5. Modifying the Collection During Iteration
Mistake:
Modifying a collection (e.g., adding or removing elements) directly while iterating over it leads to a ConcurrentModificationException.
Example:
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("A");
list.add("A");
list.add("B");
for (String item : list) {
if (item.equals("A")) {
list.remove(item); // ConcurrentModificationException
}
}
}Exception in thread "main" java.util.ConcurrentModificationException at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1095) at java.base/java.util.ArrayList$Itr.next(ArrayList.java:1049) at com.example.programming.utils.IteratorExample.main(IteratorExample.java:15)
Why It Happens:
Java iterators are fail-fast. They detect structural modifications to the collection after the iterator is created.
Solution:
Use the iterator’s remove() method instead of modifying the collection directly.
Corrected Code:
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
if (iterator.next().equals("A")) {
iterator.remove(); // Safe removal
}
}Conclusion
Java iterators are an integral part of the Java Collections Framework, providing an efficient and consistent way to traverse and manipulate collections. While enhanced for-loops offer simplicity, iterators remain essential for scenarios demanding removal or advanced traversal capabilities. By mastering iterators and their variations like ListIterator, developers can harness the full potential of Java’s collection utilities to build robust and efficient applications.
This article was originally published on Medium.



