Question 25 · Section 4

What is the difference between Iterator and ListIterator?

LinkedList.get(i) starts from head/tail each time and steps i times through links. ListIterator reaches the needed node once and then moves with O(1) — it stores a reference to...

Language versions: English Russian Ukrainian

🟢 Junior Level

Iterator — for iterating over any collections (forward only). ListIterator — for lists (forward and backward).

// Iterator: works with List, Set, Queue
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    String s = it.next();
}

// ListIterator: List only, but more powerful
ListIterator<String> it = list.listIterator();
while (it.hasNext()) {
    String s = it.next();
    // Can go backward!
    if (it.hasPrevious()) {
        String prev = it.previous();
    }
}

🟡 Middle Level

Comparison

  Iterator ListIterator
Collections All (List, Set, Queue) List only
Direction Forward only Forward and backward
Indices No nextIndex(), previousIndex()
Modification remove() remove(), set(), add()
Start From the beginning From any index

Cursor between elements

List: [A] [B] [C]
       ↑
    Cursor (between A and B)

it.next()     → returns B, cursor moves right
it.previous() → returns A, cursor moves left

ListIterator vs for (int i...): for (int i...) for LinkedList = O(n^2), because each get(i) iterates from the start. ListIterator = O(n), because it remembers the current position. For ArrayList, both approaches are O(n).

LinkedList optimization

// ❌ O(n²) — each get iterates!
for (int i = 0; i < list.size(); i++) {
    list.get(i);  // O(n) for LinkedList
}

// ✅ O(n) — iterator is already in place
ListIterator<String> it = list.listIterator();
while (it.hasNext()) {
    it.next();      // O(1)
    it.add("new");  // O(1) — already at the node!
}

LinkedList.get(i) starts from head/tail each time and steps i times through links. ListIterator reaches the needed node once and then moves with O(1) — it stores a reference to the current Node.


🔴 Senior Level

When NOT to use ListIterator

  1. Working with Set/Queue — ListIterator is not supported
  2. Simply reading elements — for-each is cleaner
  3. Need parallel processing — Iterator is simpler

Modification methods

// add(E) — inserts BEFORE the cursor
it.add("X");
// it.previous() will return "X"

// set(E) — replaces the LAST element returned by next/previous
it.next();  // → "A"
it.set("B"); // "A" → "B"

// ❌ IllegalStateException if next/previous was not called
it.set("X");  // Error!

forEachRemaining (Java 8+)

Iterator<String> it = list.iterator();
it.forEachRemaining(System.out::println);
// → Remaining elements

LinkedList optimization

LinkedList.get(500) → 500 node traversals
ListIterator at position 500:
  → add/remove/set → O(1)
  → Already holds a reference to the Node!

Best Practices

  1. Iterator → for all collections
  2. ListIterator → for List, especially LinkedList
  3. Cursor between elements
  4. set/add depend on the last next/previous
  5. listIterator(index) → start from a position
  6. forEachRemaining → Java 8+ functional style

Summary for Senior

  • Iterator = universal, forward only
  • ListIterator = List, bidirectional, modification
  • Cursor between elements
  • LinkedList → ListIterator is critical for O(1)
  • set/add → after next/previous

🎯 Interview Cheat Sheet

Must know:

  • Iterator works with all collections (List, Set, Queue), forward only
  • ListIterator for List only, but supports: backward movement, indices, set(), add()
  • ListIterator cursor is BETWEEN elements — next() returns the element to the right, previous() — to the left
  • For LinkedList: for (int i...) = O(n^2), ListIterator = O(n)
  • set() and add() work only after calling next() or previous()
  • listIterator(index) allows starting iteration from any position
  • forEachRemaining() (Java 8+) — functional style for remaining elements

Frequent follow-up questions:

  • Why is for (int i...) for LinkedList O(n^2)? — Each get(i) steps from the start/end through nodes; n calls × n steps = O(n^2).
  • When does ListIterator.add(“X”) insert the element? — Before the cursor; the next previous() will return “X”.
  • Can ListIterator be used with HashSet? — No, Set does not support ListIterator — only regular Iterator.
  • What happens if you call set() without a prior next()?IllegalStateException — there is no “last element” to replace.

Red flags (DO NOT say):

  • “ListIterator works with Set” — no, only with List
  • “Iterator can move backward” — no, only ListIterator has previous()
  • for (int i...) and ListIterator are equally efficient for LinkedList” — no, O(n^2) vs O(n)
  • set() replaces the next element” — no, it replaces the last one returned by next()/previous()

Related topics:

  • [[28. How to properly remove elements during iteration]]
  • [[26. What are fail-fast and fail-safe iterators]]
  • [[27. What is ConcurrentModificationException]]