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
EasyLet'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 genericIterator<T>interface with two methods:hasNext()that returns a boolean indicating if more elements exist, andnext()that returns the next element of type T.Playlist.java: Create the aggregate class that holds your songs. YourPlaylistshould store songs in a String array with a fixed capacity (passed to the constructor) and track how many songs have been added. Include anaddSong(String song)method to add songs to the playlist.Your Playlist needs a
createIterator()method that returns anIterator<String>. Implement this by creating a private inner class calledPlaylistIteratorthat 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 simpleSongclass that wraps a song title. It should have a constructor that takes the title (String), agetTitle()method, and atoString()method that returnsPlaying: [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
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsFields (Attributes)Constructor MethodConstructor OverloadingRecap - Simple Calculator4Inheritance
Basic Inheritance (extends)The super KeywordMethod Overriding (@Override)Constructor ChainingThe Object ClassSingle & Multilevel InheritWhy No Multi Class InheritRecap - Employee Hierarchy7Special Methods & Object Class
toString() Methodequals() and hashCode()clone() MethodcompareTo() and ComparableComparator InterfaceRecap - Custom Sorting2Access Modifiers & Encapsulate
Access Levels OverviewGetter and Setter MethodsInformation HidingThe final KeywordRecap - Bank Account Manager5Polymorphism
Method Overloading BasicsMethod Overriding (Run-Time)Upcasting and DowncastingThe instanceof OperatorAbstract Classes and MethodsRecap - Shape Calculator8Advanced OOP Concepts
Composition vs InheritanceAggregation vs CompositionInner Nested & Anonymous ClassEnums and Enum MethodsRecords (Java 16+)Sealed Classes (Java 17+)3Class Props & Static Member
Instance vs Static VariablesStatic MethodsStatic BlocksConstants (static final)Recap - Counter & Utility6Interfaces & Abstract Classes
Introduction to InterfacesImplementing InterfacesMulti Interface ImplemenDefault & Static in InterfaceAbstract Classes vs InterfacesFunctional InterfacesRecap - Payment System9Generics
Introduction to GenericsGeneric ClassesGeneric MethodsBounded Type ParametersWildcards (?, extends, super)Recap - Generic Container12Design Patterns Part 2
Command PatternAdapter PatternDecorator PatternTemplate Method PatternState PatternComposite PatternIterator Pattern