Menu
Coddy logo textTech

Iterator Pattern

Part of the Object Oriented Programming section of Coddy's Java journey — lesson 76 of 87.

The Iterator Pattern is a behavioral design pattern that provides a way to access elements of a collection sequentially without exposing its underlying structure. Whether you're working with an array, linked list, or tree, the iterator gives you a uniform way to traverse the elements.

The pattern separates the traversal logic from the collection itself. It involves two main components: an Iterator interface that defines methods for traversing elements, and an Iterable (or Aggregate) that creates iterators for its collection:

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

interface Container<T> {
    Iterator<T> createIterator();
}

class BookShelf implements Container<String> {
    private String[] books;
    private int count = 0;
    
    public BookShelf(int size) {
        books = new String[size];
    }
    
    public void addBook(String book) {
        books[count++] = book;
    }
    
    public Iterator<String> createIterator() {
        return new BookIterator();
    }
    
    private class BookIterator implements Iterator<String> {
        private int index = 0;
        
        public boolean hasNext() {
            return index < count;
        }
        
        public String next() {
            return books[index++];
        }
    }
}

The iterator maintains its own traversal state, allowing multiple iterators to traverse the same collection independently. Clients use the iterator without knowing how the collection stores its data:

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

Iterator<String> iterator = shelf.createIterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

Java's built-in Iterable and Iterator interfaces follow this exact pattern, which is why you can use enhanced for-loops with any class that implements Iterable. The Iterator Pattern is essential when you need to provide multiple traversal methods or hide complex internal structures from client code.

challenge icon

Challenge

Easy

Let's build a playlist system using the Iterator Pattern! You'll create a music playlist that stores songs and provides a custom iterator to traverse through them sequentially—without exposing how the songs are stored internally. This is a perfect use case for the Iterator Pattern, letting users navigate your collection through a clean, uniform interface.

You'll organize your code across four files:

  • Iterator.java: Define your generic Iterator<T> interface with two methods: hasNext() that returns a boolean indicating if more elements exist, and next() that returns the next element of type T.
  • Playlist.java: Create the aggregate class that holds your songs. Your Playlist should store songs in a String array with a fixed capacity (passed to the constructor) and track how many songs have been added. Include an addSong(String song) method to add songs to the playlist.

    Your Playlist needs a createIterator() method that returns an Iterator<String>. Implement this by creating a private inner class called PlaylistIterator that implements your Iterator interface. This inner iterator maintains its own index position and traverses through the songs array, returning each song in order.

  • Song.java: Create a simple Song class that wraps a song title. It should have a constructor that takes the title (String), a getTitle() method, and a toString() method that returns Playing: [title].
  • Main.java: Bring your iterator system together! You'll receive one input: a comma-separated list of song titles (for example: Bohemian Rhapsody,Stairway to Heaven,Hotel California).

    Create a Playlist with capacity for 10 songs. Parse the input and add each song title to the playlist. Then obtain an iterator from the playlist and use it to traverse through all songs, printing each one wrapped in a Song object (which will display as Playing: [title]).

    After iterating through all songs, print Playlist complete! on a new line.

You will receive one input: a comma-separated string of song titles.

For example, with input Yesterday,Imagine,Let It Be, your output would be:

Playing: Yesterday
Playing: Imagine
Playing: Let It Be
Playlist complete!

Notice how your Main class uses the iterator's hasNext() and next() methods to traverse the playlist without knowing anything about the underlying array structure. The iterator encapsulates all the traversal logic, keeping the collection's internal representation hidden from client code!

Cheat sheet

The Iterator Pattern is a behavioral design pattern that provides a way to access elements of a collection sequentially without exposing its underlying structure.

The pattern separates traversal logic from the collection itself using two main components:

  • Iterator interface: defines methods for traversing elements
  • Iterable/Container: creates iterators for its collection

Basic Structure

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

interface Container<T> {
    Iterator<T> createIterator();
}

Implementation Example

class BookShelf implements Container<String> {
    private String[] books;
    private int count = 0;
    
    public BookShelf(int size) {
        books = new String[size];
    }
    
    public void addBook(String book) {
        books[count++] = book;
    }
    
    public Iterator<String> createIterator() {
        return new BookIterator();
    }
    
    private class BookIterator implements Iterator<String> {
        private int index = 0;
        
        public boolean hasNext() {
            return index < count;
        }
        
        public String next() {
            return books[index++];
        }
    }
}

Usage

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

Iterator<String> iterator = shelf.createIterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

The iterator maintains its own traversal state, allowing multiple iterators to traverse the same collection independently. Java's built-in Iterable and Iterator interfaces follow this pattern, enabling enhanced for-loops.

Try it yourself

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: Create a Playlist with capacity for 10 songs
        
        // TODO: Parse the input (comma-separated) and add each song title to the playlist
        
        // TODO: Obtain an iterator from the playlist using createIterator()
        
        // TODO: Use the iterator to traverse through all songs
        // For each song, wrap it in a Song object and print it
        
        // TODO: Print "Playlist complete!" after iterating through all songs
    }
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming