What does ListIterator add over a plain Iterator, and when would you use it?
answer
- Lists only: list.listIterator()
- adds hasPrevious/previous (bidirectional)
- set() replaces, add() inserts, both beyond Iterator
- nextIndex()/previousIndex() for position
- cursor sits between elements
basics
~10 sListIterator works on lists and can move both directions (hasNext/next and hasPrevious/previous). It can also add() new elements and set() (replace) the current one during traversal, and it tells you the index via nextIndex()/previousIndex().
solid answer
~40 sListIterator<E> is a subinterface of Iterator available only on List implementations (via list.listIterator()). Beyond hasNext/next/remove, it supports bidirectional traversal with hasPrevious() and previous(), positional queries with nextIndex() and previousIndex(), in-place replacement with set(E), and insertion with add(E). set() replaces the element last returned by next() or previous(); add() inserts before the element that next() would return. You can start the iterator at a given index with list.listIterator(i). The cursor sits conceptually between elements, so calling next() then previous() returns the same element. Use ListIterator when you need to walk a list backwards, edit elements in place, or splice in new elements while iterating — operations a plain Iterator can't do.
code
java · 8 linesList<Integer> nums = new ArrayList<>(List.of(1, 2, 3));
ListIterator<Integer> li = nums.listIterator();
while (li.hasNext()) {
int v = li.next();
li.set(v * 10); // replace in place -> 10, 20, 30
if (v == 2) li.add(99); // insert after 20
}
// nums == [10, 20, 99, 30]go deeper
Know that ListIterator works on lists and can go backward as well as forward, and can add/set during iteration.
List the added methods (hasPrevious/previous, nextIndex/previousIndex, set, add) and explain set vs remove vs add and the cursor-between-elements model.
Explain the IllegalStateException rules for set after add/remove, the next-then-previous quirk, and that ListIterator is the efficient way to edit a LinkedList mid-traversal.
Reason about API design (why ListIterator is List-only), O(n) vs O(1) edit costs per implementation, and when to prefer ListIterator over streams or copy-and-rebuild for in-place mutation.
## What ListIterator is **`ListIterator<E>`** is a richer iterator that *extends* `Iterator<E>` and is offered only by the **`List`** family (`ArrayList`, `LinkedList`, etc.) — because only an ordered, indexed sequence can meaningfully support going backwards and inserting at a position. You obtain it with `list.listIterator()` (starts at index 0) or `list.listIterator(index)` (starts at a chosen position). ## The cursor-between-elements model The key mental model: the cursor is a position **between** two elements, not on an element. For a 3-element list there are 4 cursor positions (before [0], between [0]/[1], between [1]/[2], after [2]). - `next()` returns the element *after* the cursor and moves the cursor forward. - `previous()` returns the element *before* the cursor and moves the cursor backward. A consequence: immediately after `next()` returns element X, calling `previous()` returns X again (the cursor just stepped back over it). This surprises people but is exactly defined by the between-elements model. ## Everything ListIterator adds over Iterator Inherited from Iterator: `hasNext()`, `next()`, `remove()`. Added: 1. **`boolean hasPrevious()`** — is there an element before the cursor? 2. **`E previous()`** — return it and step back; throws `NoSuchElementException` at the start. 3. **`int nextIndex()`** — index that `next()` would return (equals `size()` at the end). 4. **`int previousIndex()`** — index that `previous()` would return (equals `-1` at the start). 5. **`void set(E e)`** — *replace* the element last returned by `next()` or `previous()`. It does **not** move the cursor and does **not** change the list size, so it never causes a ConcurrentModificationException-style problem. Throws `IllegalStateException` if neither `next()` nor `previous()` was called, or if `add()`/`remove()` was called since. 6. **`void add(E e)`** — *insert* `e` immediately before the element `next()` would return (i.e. at the cursor). The cursor moves forward past the inserted element, so a subsequent `next()` is unaffected and a subsequent `previous()` returns the new element. After `add()`, you must call `next()`/`previous()` again before `set()`/`remove()`. ## Worked example ```java List<Integer> nums = new ArrayList<>(List.of(1, 2, 3)); ListIterator<Integer> li = nums.listIterator(); while (li.hasNext()) { int v = li.next(); li.set(v * 10); // replace in place: list becomes 10,20,30 if (v == 2) li.add(99); // insert 99 after the (now-replaced) 20 } // nums == [10, 20, 99, 30] // Walk backwards while (li.hasPrevious()) { System.out.println(li.previous()); } ``` ## set() vs remove() vs add() - **`set()`**: replace current — non-structural, size unchanged. - **`remove()`**: delete the last returned element — structural. - **`add()`**: insert at cursor — structural. After a structural op (`add`/`remove`), `set()` is illegal until the next `next()`/`previous()`. ## Performance note On `ArrayList`, `add()`/`remove()` in the middle is O(n) (elements shift). On `LinkedList`, a ListIterator at a position can insert/remove in O(1) at that node — which is the *only* efficient way to do bulk middle edits on a LinkedList, since random-access `get(i)` is O(n). This makes ListIterator the idiomatic tool for editing a LinkedList during traversal. ## Term recap - **Subinterface**: an interface that extends another, adding methods (ListIterator extends Iterator). - **Bidirectional**: can move forward and backward. - **In-place replacement (`set`)**: change an element's value without changing the list's structure/size. - **Cursor between elements**: position model where next/previous straddle the same boundary.
- Why isn't ListIterator available on a HashSet?Sets have no defined order or index, so backward traversal, positional indices, and insert-at-position have no meaning; ListIterator only makes sense for an ordered, indexed List.
- After calling next() to get element X, what does previous() return?X again — the cursor sits between elements, so previous() steps back over the element next() just returned.
saying these in an interview costs you the question
- Thinking ListIterator is available on Set or Map (it's List-only)
- Believing set() changes the list size or counts as structural
- Forgetting that next() immediately followed by previous() returns the same element
- Calling set() right after add()/remove() (throws IllegalStateException)