Java 3 min read

The Iterator Design Pattern: Loop Abstraction

Master the Iterator Pattern in Java. Learn how to access elements of a collection sequentially without exposing its underlying representation.

MR

Moshiour Rahman

Advertisement

The Problem: Exposing Internal Structure

Imagine you have a custom collection class:

class BookShelf {
    private Book[] books = new Book[100];
    private int count = 0;

    public Book getBook(int index) { return books[index]; }
    public int getCount() { return count; }
}

If a client wants to loop through all books, they must:

  1. Know it’s an array internally.
  2. Use indices: for (int i = 0; i < shelf.getCount(); i++).

If you later change the internal storage to a LinkedList, all client code breaks.

The Solution: The Iterator Pattern

The Iterator Pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

Real-Life Analogy: TV Remote Channel Surfing 📺

  • You don’t know how channels are stored (array? linked list? database?).
  • You just press Next and Previous.
  • The remote gives you a sequential way to browse without knowing the internals.

Visualizing the Pattern

Iterator Pattern

Implementation

1. The Iterator Interface

public interface Iterator<T> {
    boolean hasNext();
    T next();
}

2. The Aggregate Interface

public interface Aggregate<T> {
    Iterator<T> createIterator();
}

3. Concrete Aggregate

public class BookShelf implements Aggregate<Book> {
    private Book[] books = new Book[100];
    private int count = 0;

    public void addBook(Book book) {
        books[count++] = book;
    }

    @Override
    public Iterator<Book> createIterator() {
        return new BookShelfIterator(this);
    }

    // Package-private accessor for the iterator
    Book getBookAt(int index) {
        return books[index];
    }

    int getCount() {
        return count;
    }
}

4. Concrete Iterator

public class BookShelfIterator implements Iterator<Book> {
    private BookShelf shelf;
    private int index = 0;

    public BookShelfIterator(BookShelf shelf) {
        this.shelf = shelf;
    }

    @Override
    public boolean hasNext() {
        return index < shelf.getCount();
    }

    @Override
    public Book next() {
        return shelf.getBookAt(index++);
    }
}

Usage

BookShelf shelf = new BookShelf();
shelf.addBook(new Book("Design Patterns"));
shelf.addBook(new Book("Clean Code"));

Iterator<Book> it = shelf.createIterator();
while (it.hasNext()) {
    Book book = it.next();
    System.out.println(book.getTitle());
}

In The Wild (Real World Examples)

1. java.util.Iterator

Every Java collection implements the Iterator pattern!

List<String> list = Arrays.asList("A", "B", "C");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    System.out.println(it.next());
}

2. Enhanced For-Loop

The for-each loop is syntactic sugar for the Iterator pattern:

for (String s : list) { ... }  // Uses iterator() under the hood

Cheat Sheet

FeatureDetails
CategoryBehavioral
Problem SolvedSequential access without exposing structure
Key implementationhasNext() and next() methods
ProsEncapsulation (Hides internal collection structure)
ConsOverhead (Creating an iterator object for simple cases can be overkill)

Tips to Remember 🧠

  • “Remote Control”: You control traversal without knowing what’s inside.
  • “For-Each Magic”: Any class that implements Iterable<T> can be used in a for-each loop.

Advertisement

MR

Moshiour Rahman

Software Architect & AI Engineer

Share:
MR

Moshiour Rahman

Software Architect & AI Engineer

Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.

Related Articles

Comments

Comments are powered by GitHub Discussions.

Configure Giscus at giscus.app to enable comments.