Back to Iterator & Removing During Iteration
Q2Question 2 of 3

What is the difference between Iterator and ListIterator?

Key Concepts
  • Iterator is forward-only and works on any Collection; it supports hasNext(), next(), and remove()
  • ListIterator extends Iterator for Lists only; it adds backward traversal, add(), set(), and index tracking
  • ListIterator is the only way to safely add or replace elements during iteration without CME
  • ListIterator can start at any index: list.listIterator(5) begins before the element at index 5
  • LinkedList benefits most from ListIterator because add/remove at the current position is O(1)
  • Iterator is the safer default for simple traversal; ListIterator is for bidirectional or in-place modification

Definition

Iterator traverses any Collection forward-only with remove(); ListIterator extends it for Lists with backward traversal, add(), set(), and index tracking.
  • Iterator (java.util.Iterator): works on any Collection, forward-only with hasNext()/next(), can only remove() the last returned element
  • ListIterator (java.util.ListIterator): extends Iterator for List only, adds hasPrevious()/previous() for backward traversal, add(e) to insert, set(e) to replace, and nextIndex()/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) |

JAVA
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());
    }
}
TEXT
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.
JAVA
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));
    }
}
TEXT
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

JAVA
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

DIAGRAM
  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.

---

Share
Use ← → arrow keys to navigate