Part 9 — Iterators Deep Dive¶
This topic is frequently combined with questions about ArrayList, HashMap, and concurrency.
Typical interview questions:
- What is an Iterator?
- What is
modCount? - What is a fail-fast iterator?
- What is the difference between fail-fast and fail-safe?
- Why does
ConcurrentModificationExceptionoccur? - Can you safely remove elements while iterating?
1. Why Do We Need an Iterator?¶
Suppose we have:
List<String> list = List.of("Java", "Python", "Go");
Without an iterator:
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
Works for ArrayList.
But what about:
HashSetTreeSetHashMapLinkedHashSet
They don't support index-based access.
A common traversal mechanism was needed.
That mechanism is the Iterator.
2. Iterable Hierarchy¶
Iterable
│
Collection
│
List
Set
Queue
Iterable defines one important method:
Iterator<E> iterator();
This enables:
for (String s : list) {
System.out.println(s);
}
The enhanced for loop internally uses an Iterator.
3. Iterator Interface¶
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
Three core methods.
4. hasNext()¶
Checks whether another element exists.
Example:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
5. next()¶
Returns the next element.
Example:
Iterator<Integer> it = list.iterator();
System.out.println(it.next());
Output:
10
Calling next() after the iterator is exhausted throws:
NoSuchElementException
6. remove()¶
Removes the last element returned by next().
Example:
Iterator<Integer> it = list.iterator();
while (it.hasNext()) {
Integer value = it.next();
if (value % 2 == 0) {
it.remove();
}
}
This is the correct way to remove elements during iteration.
7. What Happens Internally?¶
Suppose:
ArrayList
0 1 2 3
A B C D
Iterator:
cursor = 0
Call:
next();
Returns:
A
Cursor becomes:
1
8. Enhanced for Loop¶
Code:
for (String s : list) {
System.out.println(s);
}
Compiler roughly converts it to:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
This is why iterator rules also apply to enhanced for loops.
9. modCount¶
Interview favorite.
Collections such as ArrayList maintain:
transient int modCount;
Every structural modification increments it.
Example:
list.add("Java");
Internally:
modCount++
10. Expected Modification Count¶
When an iterator is created:
Iterator<String> it = list.iterator();
The iterator stores:
expectedModCount = modCount
11. Fail-Fast Iterator¶
During iteration:
it.next();
Internally:
expectedModCount == modCount ?
If:
Yes
Continue.
Otherwise:
ConcurrentModificationException
12. Example¶
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
for (Integer i : list) {
list.remove(i);
}
Throws:
ConcurrentModificationException
Why?
The iterator detects that the collection was structurally modified outside the iterator.
13. Correct Removal¶
Iterator<Integer> it = list.iterator();
while (it.hasNext()) {
Integer i = it.next();
if (i == 2) {
it.remove();
}
}
Safe.
Reason:
The iterator updates its own bookkeeping (expectedModCount) after a successful remove().
14. Fail-Fast vs Fail-Safe¶
Fail-Fast¶
Examples:
- ArrayList
- HashMap
- HashSet
- TreeMap
Behavior:
Modification
↓
ConcurrentModificationException
Fail-Safe¶
Examples:
- CopyOnWriteArrayList
- ConcurrentHashMap (its iterators are weakly consistent, not true fail-safe)
Behavior:
Iteration
↓
Uses snapshot or weakly consistent view
↓
No ConcurrentModificationException
15. CopyOnWriteArrayList¶
Example:
CopyOnWriteArrayList<Integer> list =
new CopyOnWriteArrayList<>();
Iterator:
Snapshot
↓
Iterate over old array
Meanwhile:
list.add(100);
No exception.
The iterator continues over the original snapshot.
16. Weakly Consistent Iterators¶
ConcurrentHashMap iterators:
- Do not throw
ConcurrentModificationException. - May reflect some updates made after iteration begins.
- Are not snapshot iterators.
Interview correction:
Many candidates incorrectly call them "fail-safe." The JDK documentation describes them as weakly consistent.
17. ListIterator¶
Extends Iterator.
Additional features:
ListIterator<E>
Supports:
- Forward traversal
- Backward traversal
- Add
- Set
- Previous index
Methods:
previous()
hasPrevious()
add()
set()
18. Example¶
ListIterator<String> it =
list.listIterator();
while (it.hasNext()) {
System.out.println(it.next());
}
while (it.hasPrevious()) {
System.out.println(it.previous());
}
Can move in both directions.
19. Enumeration¶
Legacy interface.
Methods:
hasMoreElements()
nextElement()
Used by:
Vector
Hashtable
No remove operation.
Modern Java code generally uses Iterator.
20. Iterator vs ListIterator¶
| Feature | Iterator | ListIterator |
|---|---|---|
| Forward | Yes | Yes |
| Backward | No | Yes |
| Add | No | Yes |
| Set | No | Yes |
| Remove | Yes | Yes |
| Works for | All Collections | Lists only |
21. Iterator vs Enumeration¶
| Iterator | Enumeration |
|---|---|
| Modern | Legacy |
| Remove supported | No remove |
| Fail-fast | No fail-fast behavior |
22. Why ConcurrentModificationException?¶
Example:
for (Integer i : list) {
list.add(100);
}
Process:
Iterator created
↓
expectedModCount = 3
↓
list.add()
↓
modCount = 4
↓
Iterator checks
↓
Mismatch
↓
ConcurrentModificationException
23. Does ConcurrentModificationException Mean Multiple Threads?¶
No.
Single thread:
for (Integer i : list) {
list.remove(i);
}
Still throws.
The exception indicates an unexpected structural modification during iteration, not necessarily multiple threads.
24. HashMap Iterator¶
Iterator<Map.Entry<K,V>> it =
map.entrySet().iterator();
Recommended traversal:
while (it.hasNext()) {
Map.Entry<K,V> entry = it.next();
System.out.println(
entry.getKey() + " " +
entry.getValue()
);
}
25. Safe Removal From HashMap¶
Iterator<Map.Entry<Integer,String>> it =
map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer,String> e = it.next();
if (e.getKey() == 5)
it.remove();
}
Safe.
26. Time Complexity¶
| Operation | Complexity |
|---|---|
| hasNext | O(1) |
| next | O(1) |
| remove | O(1) average (depends on collection) |
Production Examples¶
Removing Invalid Users¶
Iterator<User> it = users.iterator();
while (it.hasNext()) {
if (!it.next().isActive()) {
it.remove();
}
}
Iterating Over Cache¶
for (Map.Entry<String, User> e :
cache.entrySet()) {
process(e.getValue());
}
Common Interview Questions¶
Q1. Why do we need an Iterator?¶
To provide a uniform traversal mechanism across different collection implementations.
Q2. Why doesn't HashSet support indexing?¶
Because it is hash-table based.
There is no logical index.
Q3. What is fail-fast?¶
An iterator that detects unexpected structural modification and throws ConcurrentModificationException.
Q4. What is modCount?¶
An internal counter tracking structural modifications to the collection.
Q5. Does ConcurrentModificationException guarantee concurrent threads?¶
No.
It can occur in a single thread.
Q6. Which method should be used to remove elements while iterating?¶
Iterator.remove();
Q7. Difference between fail-fast and weakly consistent iterators?¶
| Fail-Fast | Weakly Consistent |
|---|---|
Throws ConcurrentModificationException | Does not throw it |
| Detects unexpected modification | May reflect some concurrent changes |
Examples: ArrayList, HashMap | ConcurrentHashMap |
Q8. Difference between Iterator and ListIterator?¶
ListIterator supports bidirectional traversal and element insertion/replacement.
Q9. Can you modify a collection while iterating?¶
Yes, but only through the iterator's supported modification methods (such as remove()), or by using collections designed for concurrent modification.
Q10. Why is Iterator.remove() safe?¶
Because it keeps the iterator's internal modification count synchronized with the collection.
Senior Interview Scenario¶
Question:
Why does this fail?
for (String s : list) {
if (s.equals("Java"))
list.remove(s);
}
Answer:
The enhanced for loop uses an Iterator internally.
Calling list.remove() modifies the collection directly, increasing modCount.
The iterator's expectedModCount no longer matches, so the next iterator operation throws ConcurrentModificationException.
Correct solution:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if (it.next().equals("Java")) {
it.remove();
}
}
Key Takeaways¶
Iteratorprovides a common traversal API for collections.- Enhanced
forloops use anIteratorinternally. - Fail-fast iterators rely on
modCountandexpectedModCount. ConcurrentModificationExceptioncan occur even in a single thread.Iterator.remove()is the correct way to remove elements during iteration.ListIteratorsupports bidirectional traversal and additional modification operations.ConcurrentHashMapiterators are weakly consistent, not snapshot iterators.
Next: Part 10 — Comparable vs Comparator Deep Dive¶
We'll cover:
- Natural ordering vs custom ordering
compareTo()internals- Comparator chaining
- Lambda comparators
- TimSort (
Collections.sort()/List.sort()) - Multi-field sorting
- Common contract violations
- Senior interview questions and production examples