skip to content

Iterator & ListIterator

Iterator's hasNext, next and remove, and ListIterator's bidirectional traversal with add and set. The practical rule is that removing during iteration must go through the iterator, not the collection.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

5

What is the Iterator interface in Java, and what are its core methods?

level: juniorimportance: must knowfreq 75%

answer

  1. hasNext / next / remove
  2. next() past end -> NoSuchElementException
  3. remove() is optional, acts on underlying collection
  4. for-each is sugar over iterator()
  5. Iterable gives you the Iterator

basics

~20 s

Iterator is an object that walks through a collection one element at a time. You call hasNext() to check if more elements remain, next() to get the next one, and remove() to delete the last element returned.

solid answer

~40 s

Iterator<E> is the standard Java interface for traversing a collection element by element, independent of how the collection stores its data. Its three methods are hasNext() (returns true if there are more elements), next() (returns the next element and advances the cursor), and the optional remove() (deletes the element last returned by next() from the underlying collection). Any class implementing Iterable<E> exposes an iterator via iterator(), which is what the enhanced for-each loop uses under the hood. Calling next() when hasNext() is false throws NoSuchElementException. Iterator gives a uniform traversal contract across ArrayList, HashSet, LinkedList, and more, so callers don't depend on the concrete collection type.

go deeper

for a junior

Name the three methods and write the basic while(hasNext()) loop correctly, including checking hasNext() before next().

for a middle

Explain Iterable vs Iterator, that for-each desugars to iterator()/hasNext()/next(), and that remove() acts on the backing collection and is optional.

for a senior

Discuss the Iterator pattern's purpose (decoupling traversal from storage), the exact exception contract (NoSuchElementException, IllegalStateException, UnsupportedOperationException), and forEachRemaining.

for a principal

Frame Iterator as the abstraction boundary that lets the collections framework evolve storage independently of consumers; weigh it against streams/Spliterator for parallel traversal and discuss API contract design (optional operations).

## The problem Iterator solves A **collection** is an object that holds a group of elements (a list, a set, a map's keys, etc.). Different collections store elements differently: an `ArrayList` uses a backing array, a `LinkedList` uses chained nodes, a `HashSet` uses hash buckets. If you wanted to loop over each one, you'd need to know its internal layout — array indices for one, node pointers for another. That couples your code to the implementation. The **Iterator** is the answer: a small object whose only job is to produce a collection's elements one at a time, hiding *how* they're stored. This is the classic **Iterator design pattern**: separate traversal from the container. ## The Iterable / Iterator pair Two interfaces work together: - **`Iterable<E>`** — implemented by the collection itself; it has one method, `iterator()`, which returns a fresh `Iterator<E>`. - **`Iterator<E>`** — the cursor object that actually walks the elements. Because `Collection<E>` extends `Iterable<E>`, every standard collection can hand you an iterator. ## The three methods of Iterator<E> 1. **`boolean hasNext()`** — returns `true` if calling `next()` would return an element (i.e. there is at least one more). It does *not* advance; you can call it repeatedly. 2. **`E next()`** — returns the next element and moves the internal **cursor** forward by one. If there is no next element, it throws **`NoSuchElementException`**. So the safe idiom is always: check `hasNext()` first, then call `next()`. 3. **`default void remove()`** — removes from the *underlying collection* the element that the most recent `next()` returned. It is **optional**: implementations that back an immutable or fixed view may throw `UnsupportedOperationException`. Calling `remove()` before any `next()`, or twice in a row, throws `IllegalStateException`. ## The standard loop ```java Iterator<String> it = list.iterator(); while (it.hasNext()) { String s = it.next(); // use s } ``` ## Relationship to for-each The enhanced `for (String s : list) { ... }` loop is **syntactic sugar** the compiler rewrites into exactly the `hasNext()/next()` loop above. That is why for-each works on anything `Iterable` — but it also means you cannot call `it.remove()` inside a for-each, because the iterator is hidden from you. ## Key terms recap - **Cursor**: the iterator's notion of "where am I" — conceptually a position *between* elements that advances on each `next()`. - **NoSuchElementException**: thrown by `next()` past the end. - **Optional operation**: a method the interface declares but an implementation may refuse with `UnsupportedOperationException`. Since Java 8, `Iterator` also has a default `forEachRemaining(Consumer)` that drains the rest of the elements into a lambda, but `hasNext`/`next`/`remove` remain the core contract.

  • What exception does next() throw when there are no more elements?
    NoSuchElementException.
  • Why can't you remove elements via the iterator inside a for-each loop?
    Because for-each hides the iterator object, so you have no reference to call remove() on; you must use an explicit Iterator loop instead.

saying these in an interview costs you the question

  • Thinking remove() takes an argument (it removes the last element returned by next())
  • Believing next() is safe to call without checking hasNext()
  • Confusing Iterable (the collection) with Iterator (the cursor)
  • Assuming you can call it.remove() inside a for-each loop

context

open as a page

How do you safely remove elements from a collection while iterating over it, and why is collection.remove() inside a loop dangerous?

level: middleimportance: must knowfreq 80%

basics

~10 s

Use the iterator's own remove() method, not the collection's. Calling list.remove() while looping with a for-each usually throws ConcurrentModificationException because the collection changed behind the iterator's back.

open as a page

What does ListIterator add over a plain Iterator, and when would you use it?

level: middleimportance: should knowfreq 60%

basics

~10 s

ListIterator 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().

open as a page

Explain the difference between fail-fast and fail-safe (weakly consistent) iterators in Java, with examples.

level: seniorimportance: should knowfreq 55%

basics

~10 s

Fail-fast iterators (like ArrayList's or HashMap's) throw ConcurrentModificationException if the collection changes during iteration. Fail-safe iterators (like CopyOnWriteArrayList's or ConcurrentHashMap's) iterate over a snapshot or tolerate changes without throwing.

open as a page

How would you make your own class iterable with the for-each loop, and what is the contract you must satisfy?

level: seniorimportance: nice to knowfreq 45%

basics

~10 s

Implement the Iterable<T> interface and provide an iterator() method that returns an Iterator<T>. The iterator needs hasNext() and next() (and optionally remove()). Then your object works in a for-each loop.

open as a page