DEV Community

Cover image for Iterator Design Pattern in Java – Complete Guide
ZeeshanAli-0704
ZeeshanAli-0704

Posted on

Iterator Design Pattern in Java – Complete Guide

πŸ“š Table of Contents


πŸŒ€ Iterator Design Pattern in Java – Explained with a Custom User Management Example

πŸ“Œ What is the Iterator Design Pattern?

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

Think of it as a clean way to loop through complex data structures like trees, graphs, or even simple collections, without the caller needing to know how the elements are stored internally.


πŸ§‘β€πŸ€β€πŸ§‘ Key Participants

In the context of our example:

Pattern Role Java Class
Iterator MyIterator
Concrete Iterator MyIneratorImpl
Aggregate UserManagement
Concrete Elements User

πŸ›’ Real world Analogy

Think of user management in a web app. The admin doesn’t care how users are stored (array, list, map). They just want to browse user profiles one by one β€” next user, next user...

That’s what the iterator does β€” lets the admin move across users without exposing the backend logic.


πŸ“Š UML Diagram (Text Format)

        +--------------------+       +------------------------+
        |    MyIterator      |<------+    MyIneratorImpl      |
        +--------------------+       +------------------------+
        | +hasNext():boolean |       | -list: List<User>      |
        | +next(): Object     |       | -index: int            |
        +--------------------+       | +hasNext()             |
                                      | +next()                |
                                      +------------------------+

        +------------------------+
        |   UserManagement       |
        +------------------------+
        | -list: List<User>      |
        | +addUser(User)         |
        | +getIterator():Iterator|
        +------------------------+

        +-------------+
        |   User      |
        +-------------+
        | -name       |
        | -emailID    |
        | +getName()  |
        | +getEmailID()|
        +-------------+
Enter fullscreen mode Exit fullscreen mode

πŸ’» Full Java Implementation

1. User – The Element Object

package org.example;

public class User {
    private String name;
    private String emailID;

    public User(String name, String emailID) {
        this.name = name;
        this.emailID = emailID;
    }

    public String getName() {
        return name;
    }

    public String getEmailID() {
        return emailID;
    }
}
Enter fullscreen mode Exit fullscreen mode

2. MyIterator – The Iterator Interface

package org.example;

public interface MyIterator {
    boolean hasNext();
    Object next();
}
Enter fullscreen mode Exit fullscreen mode

3. MyIneratorImpl – Concrete Iterator

package org.example;

import java.util.List;

public class MyIneratorImpl implements MyIterator {
    private List<User> list;
    private int index;

    public MyIneratorImpl(List<User> list) {
        this.list = list;
        this.index = 0;
    }

    public boolean hasNext() {
        return index < list.size();
    }

    public Object next() {
        return list.get(index++);
    }
}
Enter fullscreen mode Exit fullscreen mode

4. UserManagement – Aggregate Class

package org.example;

import java.util.ArrayList;

public class UserManagement {
    private ArrayList<User> list = new ArrayList<>();

    public void addUser(User user) {
        list.add(user);
    }

    public MyIterator getIterator() {
        return new MyIneratorImpl(list);
    }
}
Enter fullscreen mode Exit fullscreen mode

5. Main – Client Code

package org.example;

public class Main {
    public static void main(String[] args) {
        UserManagement userManagement = new UserManagement();

        User user1 = new User("User1", "[email protected]");
        User user2 = new User("User2", "[email protected]");

        userManagement.addUser(user1);
        userManagement.addUser(user2);

        MyIterator iterator = userManagement.getIterator();

        while (iterator.hasNext()) {
            User user = (User) iterator.next();
            System.out.println(user.getName() + " - " + user.getEmailID());
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ›  Use Cases in Real-World Systems

  • Traversing elements in custom collection classes
  • Paging through user records, log entries, or audit history
  • Abstracting tree traversal in file systems or DOM trees
  • Iterating over results of complex computations

βœ… Advantages

  • Decouples iteration logic from collection
  • Allows different traversal strategies (e.g., reverse, conditional)
  • Enables multiple iterators on same collection
  • Supports lazy evaluation if needed

❌ Disadvantages

  • Additional boilerplate code for small or simple collections
  • Requires maintenance of custom iterator classes
  • Can be error-prone if next() used without hasNext()

🧭 When to Use and When Not To Use

βœ… Use When:

  • You want to traverse a collection in a standard way
  • Internal data structure should remain hidden
  • Multiple types of iteration are needed

❌ Avoid When:

  • Java’s built-in Iterator or enhanced for-loop suffices
  • Performance is critical and abstraction adds overhead
  • Collections are simple and don’t require abstraction

πŸ”„ Internal vs External Iterators

Type Description Java Example
External Client controls iteration (our example) Custom iterator, while (hasNext)
Internal Collection controls iteration forEach(), Streams API

πŸ” Comparison with Java Built-in Iterators

Feature Our Custom MyIterator Java's Built-in Iterator
Interface name MyIterator java.util.Iterator
Generic support ❌ (Object) βœ… (Iterator<T>)
Additional methods ❌ βœ… (remove(), forEachRemaining)
Loop compatibility ❌ βœ… (Iterable) supports for-each
Preferred in practice ❌ βœ… (less code, more power)

πŸ§‘β€πŸ« Best Practices and Pitfalls

βœ… Best Practices:

  • Add type safety with generics (MyIterator<T>)
  • Check hasNext() before calling next()
  • Prefer Iterable<T> interface to support enhanced for-loop
  • Keep iterator logic inside collection class if possible

⚠️ Pitfalls:

  • Don’t call next() without hasNext() β€” may cause IndexOutOfBoundsException
  • Don’t modify list during iteration (unless supported)
  • Avoid exposing mutable internal data via next()

πŸ” Alternatives

Alternative Use When
Enhanced for-loop When implementing Iterable<T>
Java Streams When using functional and lazy operations
ListIterator When bidirectional or modifying iteration is needed
Reactive Streams For async event-based data flow

πŸ“ Summary (Bullet Points)

  • The Iterator Pattern provides a standard way to iterate collections without exposing internals.
  • We implemented MyIterator, MyIneratorImpl, UserManagement, and User to demonstrate it.
  • Separation of concerns: collection logic and iteration logic are independent.
  • Java provides built-in Iterator/Iterable that are preferable in production.
  • Consider using Streams or for-each for simpler use cases.
  • Useful in designing robust and flexible custom collection classes.


πŸ“š Explore More Design Patterns in Java


More Details:

Get all articles related to system design
Hastag: SystemDesignWithZeeshanAli

systemdesignwithzeeshanali

Git: https://github.com/ZeeshanAli-0704/SystemDesignWithZeeshanAli

Top comments (0)