JavaIterators

Iterators

An Iterator is an object that knows how to walk through a collection one element at a time, without exposing how that collection is actually stored internally. Every collection in the Java Collections Framework can produce one via its iterator() method, and it's actually what powers the enhanced for-each loop behind the scenes.
The Iterator Interface
Iterator exposes three key methods: hasNext(), which reports whether there's another element left, next(), which returns that element and advances the cursor, and remove(), which deletes the element most recently returned by next() from the underlying collection.

Manually driving an Iterator

Java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

List<String> names = new ArrayList<>(List.of("Ann", "Ben", "Cid"));
Iterator<String> it = names.iterator();

while (it.hasNext()) {
    String name = it.next();
    System.out.println(name);
}
Ann
Ben
Cid
Note
This is exactly what a for-each loop compiles down to. Writing for (String name : names) is syntactic sugar around an Iterator obtained from names.iterator().
Why You Need Iterator to Remove Safely
Removing elements from a list while looping over it with a for-each loop is a classic Java mistake. The for-each loop uses an Iterator internally, and modifying the collection through any means other than that same Iterator — such as calling list.remove() directly — invalidates it. The next call to next() then throws a ConcurrentModificationException, even though only one thread was involved.

The broken version — modifying a list during a for-each loop

Java
import java.util.ArrayList;
import java.util.List;

List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3, 4, 5));

for (Integer n : numbers) {
    if (n % 2 == 0) {
        numbers.remove(n); // throws ConcurrentModificationException
    }
}
ConcurrentModificationException
The exception is thrown as soon as the loop calls next() after the list was structurally modified outside the Iterator — the Iterator detects the change via an internal modification counter and refuses to continue with potentially stale state.
The fix is to call remove() directly on the Iterator itself, which is specifically designed to keep its internal state in sync with the removal.

The fix — removing through the Iterator

Java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3, 4, 5));
Iterator<Integer> it = numbers.iterator();

while (it.hasNext()) {
    int n = it.next();
    if (n % 2 == 0) {
        it.remove(); // safe: removes the element just returned by next()
    }
}

System.out.println(numbers);
[1, 3, 5]
ListIterator — Bidirectional Iteration
Lists offer a more capable version called ListIterator, obtained via list.listIterator(). In addition to everything Iterator provides, it can move backwards with hasPrevious()/previous(), report the current index, and even set() or add() elements during traversal — useful when you need to walk a list in either direction or modify elements in place while iterating.

ListIterator moving backwards

Java
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

List<String> letters = new ArrayList<>(List.of("A", "B", "C"));
ListIterator<String> lit = letters.listIterator(letters.size());

while (lit.hasPrevious()) {
    System.out.println(lit.previous());
}
C
B
A

Capability

Iterator

ListIterator

Forward traversal

Yes

Yes

Backward traversal

No

Yes

Safe removal during iteration

Yes (remove())

Yes (remove())

Add/replace elements during iteration

No

Yes (add()/set())

Available on

Any Collection

List implementations only

Tip
When you only need to read through a collection, a plain for-each loop is the cleanest option. Reach for an explicit Iterator when you need to remove elements while looping, and ListIterator when you need to move backwards or modify a list in place.
  • Iterator exposes hasNext(), next(), and remove()

  • The for-each loop is built on Iterator under the hood

  • Removing from a collection any other way while iterating throws ConcurrentModificationException

  • Call remove() on the Iterator itself to delete elements safely mid-loop

  • ListIterator adds backward traversal plus in-place add()/set() for lists