Design Patterns: The Iterator pattern in Java
by Riley MacDonald, October 9, 2017

The iterator pattern simplifies interactions between various objects that use different types of Collections to store data. Clients interacting with these objects shouldn’t need to know the internal details of how the data is stored, they should just be able to fetch the data by programming to interface not to implementation.

Example Problem:
Here’s a couple of example objects that store the same type of data using different types of collections (SnookerPlayers which uses an Array and PoolPlayers which uses an ArrayList). A client would need to implement two different loops (specific to the collection type) in order to access the desired data.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class Player {
    private String name;
    private double fargoRating;
 
    public Player(String name) { this.name = name; }
 
    public String getName() { return name; }
    public double getFargoRating() { return fargoRating; }
 
    // omitting the details of fargo rating
    private void updateFargoRating() { }
}
 
public class PoolPlayers {
    private final ArrayList<Player> poolPlayers;
 
    public PoolPlayers() {
        poolPlayers = new ArrayList<Player>() {{
            add(new Player("John Morra"));
            add(new Player("Shane Van Boening"));
        }};
    }
 
    public ArrayList<Player> getPoolPlayers() { return poolPlayers; }
}
 
public class SnookerPlayers {
    private Player[] snookerPlayers;
 
    public SnookerPlayers() {
        snookerPlayers = new Player[16]; // small league with one table
        snookerPlayers[0] = new Player("Mark Selby");
        snookerPlayers[1] = new Player("Judd Trump");
    }
 
    public Player[] getSnookerPlayers() { return snookerPlayers; }
}

Consider league software attempting to print a full list of players:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class League {
    SnookerPlayers snookerPlayers = new SnookerPlayers();
    PoolPlayers poolPlayers = new PoolPlayers();
 
    public League() { printNames(); }
 
    public void printNames() {
        for (int i = 0; i < snookerPlayers.getSnookerPlayers().length; i++) {
            String name = snookerPlayers.getSnookerPlayers()[i].getName();
            double fargoRating  = snookerPlayers.getSnookerPlayers()[i].getFargoRating();
 
            System.out.println(String.format("Name: %s, Fargo Rating: %s", name, fargoRating));
        }
 
        for (int i = 0; i < poolPlayers.getPoolPlayers().size(); i++) {
            String name = poolPlayers.getPoolPlayers().get(i).getName();
            double fargoRating  = poolPlayers.getPoolPlayers().get(i).getFargoRating();
 
            System.out.println(String.format("Name: %s, Fargo Rating: %s", name, fargoRating));
        }
    }
}

The loops are very closely duplicated with the exception of the methods calls specific to the collection used (get() for ArrayList and [i] for Array). The League code can be simplified by implementing the Iterator Pattern. Let’s start by having SnookerPlayer implement the Java Iterator interface and adding the necessary logic. SnookerPlayer now looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class SnookerPlayers implements Iterator {
    private Player[] snookerPlayers;
    private int position = 0;
 
    public SnookerPlayers() {
        snookerPlayers = new Player[16]; // small league with one table
        snookerPlayers[0] = new Player("Mark Selby");
        snookerPlayers[1] = new Player("Judd Trump");
    }
 
    public Player[] getSnookerPlayers() { return snookerPlayers; }
 
    @Override
    public boolean hasNext() {
        return position >= snookerPlayers.length || snookerPlayers[position] == null;
    }
 
    @Override
    public Object next() {
        Player player = snookerPlayers[position];
        position += 1;
        return player;
    }
 
    @Override
    public void remove() {
        if (position <= 0) {
            throw new IllegalStateException("Cannot remove without calling next()");
        }
 
        if (snookerPlayers[position - 1] != null) {
            for (int i = position -1; i < (snookerPlayers.length - 1); i++) {
                snookerPlayers[i] = snookerPlayers[i+1];
            }
            snookerPlayers[snookerPlayers.length - 1] = null;
        }
    }
}

Luckily our PoolPlayer doesn’t need to provide it’s own implementation of Iterator because ArrayList already provides one (iterator()). Now that we have a common Iterator interface. The League class can now be greatly simplified:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class League {
    SnookerPlayers snookerPlayers = new SnookerPlayers();
    PoolPlayers poolPlayers = new PoolPlayers();
 
    public League() {
        printNames(snookerPlayers); // now an iterator
        printNames(poolPlayers.getPoolPlayers().iterator());
    }
 
    public void printNames(Iterator iterator) {
        while (iterator.hasNext()) {
            Player player = (Player) iterator.next();
            System.out.println(String.format("Name: %s, FargoRating: %s", 
                    player.getName(), player.getFargoRating()));
        }
    }
}

Keep in mind you can write your own Iterator to support any type of Collection. If you need to write your own Iterator simply expose the Iterator on your class by creating a getter method.

Summary
Many of the Java Collections expose an Iterator which eases the implementation of this design pattern. Implementing this pattern can minimize the amount of responsibility a class has ameliorating the single responsibility principle. The above code could be simplified (Player should really be an interface) but I feel it’s a good reference example of the Iterator Pattern.

Open the comment form

Leave a comment:

Comments will be reviewed before they are posted.

User Comments:

Be the first to leave a comment on this post!