Behavioral Cursor

Iterator

Iterator is a behavioral pattern that provides a uniform way to step through the elements of a collection one at a time, without revealing whether the collection is stored as an array, a tree, a linked list, or something else.

Complexity
Popularity

Problem

A media library might store playlists as a flat array, favorites as a hash set, and a "recently played" history as a fixed-size ring buffer. Every part of the UI that needs to loop over one of these - the shuffle button, the export feature, the search filter - ends up with a different loop shape depending on which structure it's touching.

If the traversal logic is written straight into each collection class, that class now has two jobs: managing its data and knowing every way someone might want to walk through it. Adding a new traversal order, like reverse or shuffled playback, means going back into the collection class again, and switching the underlying storage later breaks every piece of client code that assumed array indexing.

Solution

Iterator moves the traversal logic out of the collection and into a dedicated companion object - the iterator - that knows how to walk that one specific structure and nothing else.

Every iterator, regardless of what it's walking, exposes the same small interface: something like "is there a next element" and "give me the next element." Client code loops using only that interface, so it never has to know or care whether it's iterating an array, a tree, or a ring buffer underneath. A collection can hand out several independent iterators at once, each tracking its own position, and a new traversal order - reverse, shuffled, filtered - is just a new iterator class sitting alongside the existing ones, leaving the collection itself untouched.

When to Use

  • Reach for Iterator when the collection's internal layout is genuinely complex and client code shouldn't need to know about it just to loop over the elements.
  • Use it to pull nearly identical traversal loops out of several places in the codebase and consolidate them behind one interface.
  • It's the right tool when the same client code needs to work across several different, or not-yet-known, kinds of data structures.

Real-World Examples

  • **The JavaScript iteration protocol** - any object exposing `Symbol.iterator` automatically works with `for...of`, the spread operator, and array destructuring.
  • **Java's `Iterable`/`Iterator` interfaces** - every collection in the Java Collections Framework implements `Iterable`, which is what lets it plug into the enhanced for-loop.
  • **Database result cursors** - a JDBC `ResultSet` or a Postgres server-side cursor streams query results row by row instead of loading the whole table into memory at once.