Java - Iterator vs ListIterator
Both Iterator and ListIterator are used to traverse collections in Java, but they differ significantly in capability. Iterator is a general-purpose, forward-only cursor for any Collection; ListIterator is a more powerful, bidirectional cursor available only for List implementations.
Contents
Comparison Table
An IteratorCollectionListIteratorListIteratorListIterator
| Feature | Iterator | ListIterator |
|---|---|---|
| Applicable to | Any Collection | Only List |
| Direction | Forward only | Forward and backward |
| Obtain via | collection.iterator() | list.listIterator() |
| Add elements | ❌ No | ✅ add(E) |
| Replace elements | ❌ No | ✅ set(E) |
| Get current index | ❌ No | ✅ nextIndex()previousIndex() |
| Remove elements | ✅ remove() | ✅ remove() |
Using Iterator
Obtain an IteratorCollectioncollection.iterator()hasNext()next()remove()
List<String> fruits = new ArrayList<>(List.of("apple", "banana", "cherry", "date"));
Iterator<String> it = fruits.iterator();
while (it.hasNext()) {
String fruit = it.next();
System.out.println(fruit);
// Safe removal during iteration (unlike list.remove() which throws CME)
if (fruit.startsWith("b")) {
it.remove(); // removes "banana"
}
}
System.out.println(fruits); // [apple, cherry, date]
Note:
Always call next()remove()remove()next()IllegalStateException
Using ListIterator
ListIteratorIterator
List<String> items = new ArrayList<>(List.of("a", "b", "c", "d"));
ListIterator<String> lit = items.listIterator();
// Forward pass — uppercase each element
while (lit.hasNext()) {
int idx = lit.nextIndex();
String val = lit.next();
lit.set(val.toUpperCase()); // replace current element
System.out.println("Index " + idx + ": " + val);
}
// items = [A, B, C, D]
// Backward pass — print in reverse
System.out.println("Reverse:");
while (lit.hasPrevious()) {
System.out.print(lit.previous() + " "); // D C B A
}
// Insert an element after "B" (start from beginning, stop at B)
ListIterator<String> insertIt = items.listIterator();
while (insertIt.hasNext()) {
if (insertIt.next().equals("B")) {
insertIt.add("B+"); // inserted after "B"
break;
}
}
System.out.println(items); // [A, B, B+, C, D]
Start from a specific index: list.listIterator(index)
ConcurrentModificationException
Both iterators are fail-fast: if the underlying collection is structurally modified (elements added or removed) through any means other than the iterator's own remove()add()ConcurrentModificationException
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
// WRONG — throws ConcurrentModificationException
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if (s.equals("b")) {
list.remove(s); // directly modifying the list!
}
}
// CORRECT — use iterator's remove()
Iterator<String> it2 = list.iterator();
while (it2.hasNext()) {
if (it2.next().equals("b")) {
it2.remove(); // safe
}
}
// ALTERNATIVE — Java 8+ removeIf (uses iterator internally)
list.removeIf(s -> s.equals("b"));
CopyOnWriteArrayListConcurrentModificationExceptionremove()When to Use Which
- Use Iterator when you need to traverse any
(includingCollection andSet ) forward-only, optionally removing elements during traversal.Queue - Use ListIterator when you need to:
- Traverse a
in both directions.List - Replace elements during traversal (
).set() - Insert elements during traversal (
).add() - Know the current index (
/nextIndex() ).previousIndex()
- Traverse a
- Use the enhanced for-loop (which uses
under the hood) when you only need to read elements without modifying the collection.Iterator - Use removeIf() (Java 8+) as a clean alternative to iterator-based removal.