How does `MutableIterator.remove()` work, and why is it the safe way to delete elements while iterating a `MutableList`?
answer
- MutableIterator = Iterator + remove()
- removes the last element returned by next()
- direct list.remove in for-loop → ConcurrentModificationException
- one remove() per next(), else IllegalStateException
- prefer removeAll { } / removeIf for bulk
basics
~10 sMutableIterator adds a remove() method that deletes the element you just returned with next(). Using it keeps the iterator consistent, so you can remove items during a loop without corrupting the traversal.
solid answer
~40 s`MutableIterable<T>` returns a `MutableIterator<T>`, which extends `Iterator<T>` with `remove()`. `remove()` deletes the **last element returned by `next()`** and is the only sanctioned way to mutate a collection mid-iteration. Calling `list.remove(x)` directly inside a `for` loop instead structurally modifies the backing collection and triggers `ConcurrentModificationException` (fail-fast) for JDK-backed lists. The correct pattern is to obtain the mutable iterator explicitly: `val it = list.iterator(); while (it.hasNext()) { if (drop(it.next())) it.remove() }`. Contract rules: `remove()` may be called only once per `next()`, and not before the first `next()` — otherwise it throws `IllegalStateException`. For bulk conditional removal, prefer the stdlib `removeAll { predicate }` / `removeIf` which encapsulate this safely. `MutableList` also exposes `MutableListIterator` with `set()` and `add()`.
code
kotlin · 6 linesval xs = mutableListOf("a", "", "b", "", "c")
val it = xs.iterator()
while (it.hasNext()) {
if (it.next().isEmpty()) it.remove()
}
println(xs) // [a, b, c]go deeper
Knows you shouldn't modify a list inside its own for loop and that iterator().remove() exists.
Explains MutableIterator.remove() semantics, the CME cause, and the IllegalStateException contract.
Discusses fail-fast modCount, when to prefer removeAll/removeIf, and MutableListIterator add/set.
Weighs imperative vs declarative removal, fail-fast vs weakly-consistent iterators, and concurrency/thread-safety implications.
## The mutable branch of the protocol Kotlin splits read-only and mutable hierarchies: - `Iterable<T>` → `Iterator<T>` (read-only: `hasNext`, `next`). - `MutableIterable<T>` → `MutableIterator<T>` which **adds** `fun remove()`. `MutableCollection<T>` extends `MutableIterable<T>`, so `MutableList`, `MutableSet` give you a `MutableIterator`. ## What `remove()` does ```kotlin public interface MutableIterator<out T> : Iterator<T> { public fun remove() } ``` It removes from the **underlying collection** the element most recently returned by `next()`. The iterator updates its own internal cursor accordingly, so traversal continues correctly past the hole. ## Why direct removal blows up JDK collection iterators are **fail-fast**: they track a `modCount`. If you mutate the list through the list API while a `for` loop's iterator is live, the next `next()`/`hasNext()` sees a `modCount` mismatch and throws `ConcurrentModificationException`. ```kotlin val xs = mutableListOf(1, 2, 3, 4) // BAD: structural modification during for-each // for (x in xs) { if (x % 2 == 0) xs.remove(x) } // CME at runtime // GOOD: iterator.remove() val it = xs.iterator() while (it.hasNext()) { if (it.next() % 2 == 0) it.remove() } println(xs) // [1, 3] ``` Going through `it.remove()` increments `modCount` *and* the iterator's expected count together, so no mismatch. ## Contract & exceptions - Call `remove()` **after** a `next()`, **once** per `next()`. - Calling it before any `next()`, or twice in a row, throws `IllegalStateException`. - Not every `MutableIterator` supports it: an iterator over an immutable view may throw `UnsupportedOperationException`. ## Higher-level alternatives (prefer these) - `mutableList.removeAll { it % 2 == 0 }` / `removeIf { ... }` — safe, expressive. - Build a new list with `filter { ... }` when immutability is acceptable. - `MutableListIterator` additionally offers `set(e)` (replace current) and `add(e)` (insert), plus bidirectional `previous()`/`previousIndex()`. Use `remove()` directly when you need element-by-element control with side effects; otherwise reach for the declarative helpers.
- What happens if you call `remove()` before the first `next()`?It throws `IllegalStateException` — there is no 'last returned' element to remove. The same happens if you call `remove()` twice without an intervening `next()`.
- When would you prefer `removeAll { }` over manual `iterator().remove()`?For declarative bulk filtering with no per-element side effects — it's clearer, safer, and avoids the imperative cursor bookkeeping. Use manual `remove()` when each removal needs custom logic mid-walk.
saying these in an interview costs you the question
- Calling `list.remove(x)` inside a `for`-each and not expecting ConcurrentModificationException
- Thinking `remove()` deletes by index or value argument (it takes none — removes last `next()`)
- Calling `remove()` twice per `next()` without knowing it throws IllegalStateException
- Assuming every iterator supports `remove()` (immutable views throw UnsupportedOperationException)
- Confusing read-only `Iterator` with `MutableIterator`