Definition
- Iterator (
java.util.Iterator): works on any Collection, forward-only withhasNext()/next(), can onlyremove()the last returned element - ListIterator (
java.util.ListIterator): extends Iterator forListonly, addshasPrevious()/previous()for backward traversal,add(e)to insert,set(e)to replace, andnextIndex()/previousIndex()for position tracking - ListIterator is the only safe way to add or modify elements during iteration
- Can start at any position:
list.listIterator(index)
Iterator is like reading a bank statement page by page from front to back – you can only go forward and can tear out (remove) a page. ListIterator is like having a bookmark that moves both forward and backward, letting you insert new pages, replace the current page, and check the page number at any time.
Understanding the Concepts
What is the difference between Iterator and ListIterator?
| Feature | Iterator | ListIterator |
|---|---|---|
| Works on | Any Collection | List only |
| Direction | Forward only | Forward + backward |
| hasNext() / next() | Yes | Yes |
| hasPrevious() / previous() | No | Yes |
| remove() | Yes | Yes |
| add(e) | No | Yes (insert at position) |
| set(e) | No | Yes (replace last returned) |
| nextIndex() / previousIndex() | No | Yes |
| Start at index | No (always from 0) | Yes: listIterator(index) |
package com.bank.demo;
import java.util.*;
public class IteratorVsListIteratorDemo {
public static void main(String[] args) {
List<String> accounts = new ArrayList<>(List.of("SAV2001", "CUR3001", "FD4001"));
// Iterator: forward-only, remove-only
System.out.println("Iterator (forward):");
Iterator<String> it = accounts.iterator();
while (it.hasNext()) {
System.out.println(" " + it.next());
}
// ListIterator: bidirectional + add + set
System.out.println("\nListIterator (add + set):");
ListIterator<String> lit = accounts.listIterator(1); // start before CUR3001
// Insert before CUR3001
lit.add("LON5001"); // [SAV2001, LON5001, CUR3001, FD4001]
// Move forward and replace CUR3001
String current = lit.next(); // CUR3001
lit.set("CUR3001-UPDATED"); // replace
// Move backward
lit.previous(); // CUR3001-UPDATED
lit.previous(); // LON5001
System.out.println("Result: " + accounts);
System.out.println("Current index: " + lit.nextIndex());
}
}
Iterator (forward):
SAV2001
CUR3001
FD4001
ListIterator (add + set):
Result: [SAV2001, LON5001, CUR3001-UPDATED, FD4001]
Current index: 1
When do you use ListIterator?
ListIterator is necessary when you need to:
- Add elements during iteration – only ListIterator.add() is safe; collection.add() during iteration throws CME.
- Replace elements during iteration – ListIterator.set() replaces the last returned element.
- Traverse backward – ListIterator.previous() moves in reverse.
- Know the current position – nextIndex() and previousIndex() give the cursor position.
package com.bank.service;
import java.util.*;
public class ListIteratorUseCaseDemo {
public static void main(String[] args) {
// Scenario: insert audit markers between transactions
List<String> transactions = new ArrayList<>(List.of(
"TXN-001: Deposit", "TXN-002: Withdraw", "TXN-003: Transfer"
));
ListIterator<String> lit = transactions.listIterator();
while (lit.hasNext()) {
String txn = lit.next();
lit.add("[AUDIT] Verified: " + txn); // insert after current
}
System.out.println("With audit markers:");
transactions.forEach(t -> System.out.println(" " + t));
}
}
With audit markers:
TXN-001: Deposit
[AUDIT] Verified: TXN-001: Deposit
TXN-002: Withdraw
[AUDIT] Verified: TXN-002: Withdraw
TXN-003: Transfer
[AUDIT] Verified: TXN-003: Transfer
What are common mistakes?
Mistake: Calling set() without calling next() or previous() first
ListIterator<String> lit = list.listIterator();
// lit.set("X"); // IllegalStateException! Must call next() or previous() first.
lit.next();
lit.set("X"); // OK – replaces the element returned by next()
What should a senior engineer know?
- ListIterator.add() inserts before the cursor. After add(), the cursor is between the inserted element and the next element. Calling next() returns the element after the inserted one; calling previous() returns the inserted element.
- LinkedList + ListIterator = O(1) insert. On LinkedList, ListIterator.add() is O(1) because it just rewires pointers. On ArrayList, it is O(n) because elements shift.
- Spliterator is the parallel alternative. For parallel processing, use Spliterator (available since Java 8) instead of Iterator.
What are common interview follow-up questions?
- "Can Iterator move backward?" – No, only ListIterator can.
- "Can you add elements during iteration?" – Only with ListIterator.add().
- "What does set() do?" – Replaces the last element returned by next() or previous().
- "Which List benefits most from ListIterator?" – LinkedList (O(1) add/remove at position).
Visual Overview
Iterator vs ListIterator
Iterator: → A → B → C → (end)
forward only, remove only
ListIterator: ← A ↔ B ↔ C → (end)
forward + backward
add, set, remove
nextIndex, previousIndex
ListIterator cursor positions:
|A|B|C| ← cursor is BETWEEN elements
^ listIterator(0): before A
^ listIterator(1): before B
^ listIterator(2): before C
^ listIterator(3): after C
Key Takeaway
Iterator is the basic forward-only cursor that works on any Collection. ListIterator extends it for Lists with backward traversal, in-place add and set, and index tracking. ListIterator is the only safe way to add or modify elements during iteration.
In the National Bank of India's compliance module, Rajesh uses a ListIterator to walk through the transaction list and insert audit markers after each entry. Because ListIterator.add() is safe during iteration, no ConcurrentModificationException occurs, and on LinkedList the insertion is O(1).
Remember one sentence: Iterator goes forward and can only remove; ListIterator goes both ways and can add, set, and remove – use it when you need to modify a List during traversal.
---