What does `ListIterator` add over a plain `Iterator`, and when would you reach for it?
answer
- ListIterator = Iterator + previous/hasPrevious + nextIndex/previousIndex
- cursor sits between elements
- MutableListIterator adds set() and add()
- only List/MutableList expose it
- listIterator(index) to start mid-list
basics
~10 sListIterator lets you walk a list both forward and backward. It adds previous(), hasPrevious(), and index queries nextIndex()/previousIndex(). The mutable version can also replace and insert elements during the walk.
solid answer
~40 s`ListIterator<T>` extends `Iterator<T>` for indexed, **bidirectional** traversal: beyond `hasNext()`/`next()` it adds `hasPrevious()`, `previous()`, `nextIndex()`, and `previousIndex()`. You get it via `list.listIterator()` or `list.listIterator(index)` to start mid-list. The cursor sits *between* elements: `nextIndex()` is the index returned by a following `next()`, and `previousIndex()` is one less. `MutableListIterator<T>` further adds `set(element)` (replace the last element returned by `next()`/`previous()`) and `add(element)` (insert before the implicit cursor), plus inherited `remove()`. Use it when you need to scan backward, replace elements in place without index bookkeeping, or insert during traversal — e.g., in-place transforms or merge-style edits. For simple forward iteration or removal, a plain `Iterator`/`MutableIterator` is lighter. Only `List`/`MutableList` expose it; `Set`/`Map` don't (no positional order contract).
code
kotlin · 6 linesval xs = mutableListOf("x", "y", "z")
val it = xs.listIterator(xs.size) // start at end
while (it.hasPrevious()) {
val i = it.previousIndex()
print("$i:${it.previous()} ")
} // 2:z 1:y 0:xgo deeper
Knows ListIterator can also go backward.
Lists the added methods (previous, hasPrevious, index queries) and that only Lists provide it.
Explains the between-elements cursor model and MutableListIterator set/add semantics including state preconditions.
Reasons about API design (why indexed bidirectional iteration is list-only), performance of in-place edits, and when rebuild-via-map is cleaner than mutation.
## Position in the hierarchy ``` Iterator<T> -> hasNext(), next() ListIterator<T> -> + hasPrevious(), previous(), nextIndex(), previousIndex() MutableIterator<T> -> + remove() MutableListIterator<T> -> ListIterator + remove(), set(e), add(e) ``` Obtain it only from a list: ```kotlin val li: ListIterator<String> = list.listIterator() val li2 = list.listIterator(startIndex) // begin partway ``` ## The 'cursor between elements' model A `ListIterator`'s cursor sits **between** elements, not on one: ``` a b c ^ ^ ^ ^ idx 0 1 2 3 (cursor positions) ``` - `nextIndex()` = index that the next `next()` would return. - `previousIndex()` = `nextIndex() - 1`. - After `next()` returns `a`, the cursor moves forward; calling `previous()` then returns `a` again (it walks back over it). ## Bidirectional walk ```kotlin val it = listOf("a", "b", "c").listIterator() while (it.hasNext()) it.next() // walk to the end while (it.hasPrevious()) print(it.previous() + " ") // c b a ``` ## Mutation with `MutableListIterator` ```kotlin val xs = mutableListOf(1, 2, 3) val it = xs.listIterator() while (it.hasNext()) { val v = it.next() it.set(v * 10) // replace current if (v == 2) it.add(99) // insert after current } println(xs) // [10, 20, 99, 30] ``` - `set(e)` replaces the element last returned by `next()`/`previous()` — needs a preceding traversal call or throws `IllegalStateException`. - `add(e)` inserts at the cursor (before the element a subsequent `next()` would return); it advances the cursor so a following `next()` skips the inserted element. - `remove()` behaves as on any `MutableIterator`. ## When to choose it - **Backward scans** or two-way passes over a `List`. - **In-place replacement** (`set`) without manual `list[i] = ...` index juggling. - **Insertion during traversal** (`add`) where rebuilding the list is awkward. - Starting iteration at an offset via `listIterator(index)`. For plain forward reading, conditional removal, or non-list collections, prefer `iterator()` — `ListIterator` is list-only and heavier in API surface.
- Why don't `Set` and `Map` expose a `ListIterator`?`ListIterator` is built on positional indices (`nextIndex`/`previousIndex`), which only make sense for ordered, indexed `List`. Sets and maps have no positional contract, so they expose only a plain (mutable) `Iterator`.
- After `add(e)` during forward iteration, will the next `next()` return the inserted element?No. `add(e)` inserts before the cursor and advances it past the new element, so a subsequent `next()` returns the element that was already next, not the inserted one. A `previous()` would return the inserted element.
saying these in an interview costs you the question
- Thinking the cursor sits on an element rather than between elements
- Expecting `Set`/`Map` to provide a `ListIterator`
- Calling `set()`/`remove()` before any `next()`/`previous()` (IllegalStateException)
- Believing `add()`-ed element is returned by the immediate next `next()`
- Confusing `nextIndex()` (next to be returned) with the current element's index