Your Guide to Design Patterns – Iterator Pattern

Design Patterns - Iterator Pattern

For the last three weeks we’ve been looking at creational factory patterns: Factory Method, Simple Factory and Abstract Factory patterns. This week we’ll cover a commonly used behavioural pattern, the Iterator pattern.

The Iterator Pattern

The Gang of Four book defines the Iterator pattern as follows:

“Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.”

This formalises the way we sequentially access the elements of a collection, without needing to know anything about the internal implementation of the collection. Using an iterator hides those internals from the client application, so that we as developers can easily change the internal code without affecting any class that uses it.

The iterator pattern has become so commonplace in modern programming languages that it has become more of a programming idiom rather than a design pattern.

While on that topic, let’s take a brief detour to look at programming idioms because the topic comes up quite often in discussions about design patterns.

Programming Idioms vs Design Patterns

Programming idioms are low-level design patterns specific to a programming language. An idiom describes how to solve implementation-specific problems using the features of that language, such as memory management in C++. Idioms use particular language features or work around a specific language deficiencies.

This is in contrast to design patterns which address general design principles. Design patterns are not specific to any language. Ideally design patterns should be language independent.

There isn’t an absolute dividing line between programming idioms and design patterns. Idioms represent low-level solutions specific to a programming language. Design patterns represent high-level language-agnostic solutions to common programming problems. Idioms often directly address the concrete implementation of a design pattern.

Another difference between an idiom and a pattern is that of size. An idiom is generally small, like “use an interface type for a collection variable”, while patterns tend to represent larger solutions.

Iterator Pattern in the Java Collection API

The usual way that the iterator pattern is implemented is by defining a separate iterator object that has the responsibility of accessing and traversing the collection object. A method is then defined in the collection to return an iterator object.

In Java, all of the collection classes in the java.util package implement the Iterator pattern to step through the collection. The top-level Collection interface defines an iterator() method that returns an Iterator object.

The important methods of the Java Iterator interface are shown below:

public interface Iterator {
   public boolean hasNext();
   public E next();
   public default void remove();
}

The hasMore() method returns a boolean result to indicate that the collection has more elements. The next() method returns a reference to the next element in the collection. The remove() method removes the last element returned by the iterator (this is optionally supported). Each concrete collection implements these methods in its own way (i.e. polymorphically).

Most other modern programming languages also have collection and record set classes that implement the Iterator pattern.

Iterator Pattern: Example Code

Back in our first person shooter game, we’ve equipped all our soldiers with weapons (see the previous post on the Template Method design pattern). During the game, we can find new weapons, and possibly even lose a weapon or have it taken away from us during a fight.

We’d occasionally like to take stock and see what weapons we have. We’d like to choose the best weapon for the occasion. Stakes and decapitation work on a Vampire. We need to shoot a Werewolf with a silver bullet. And anything that can destroy the brains of a Zombie will do the trick.

How do we check all our weapons? With an iterator, of course!

import java.util.*;

public abstract class BaseSoldier {

    // Weapon collection - an ArrayList is used here for illustration.
    // We'd create an appropriate concrete collection in the constructor.

    private Collection weapons = new ArrayList<>();
    private Weapon currentWeapon;

    // checking weapons
    public void checkWeapons() {

        // using the iterator
        Iterator it = weapons.iterator();
        while (it.hasNext()) {
            Weapon weapon = it.next();
            // check if a weapon is appropriate for the task
            // at hand, then set it to the current weapon.
            ...
            currentWeapon = weapon;
        }
    }

    // more BaseSoldier code

} // end of class

The checkWeapons() method doesn’t know or care how the weapons are stored. It uses the iterator to sequentially access the weapons one at a time. The weapons collection could refer to any concrete class implementing the Collection interface, and the iterator would work identically.

Fail-fast and Fail-safe Iterators in Java

If necessary, we could expose the collection of weapons to client code for external iteration, though we’d have to take care to avoid concurrent modification of the collection by both the BaseSoldier code and the client code. Different concrete collection classes have different behaviours which have to be handled appropriately.

Iterators over ArrayList and HashMap views are fail-fast. If the collection is modified at any time after the iterator is created, other than with the iterator’s remove() method, the iterator will throw a ConcurrentModificationException. This means that the iterator fails quickly and cleanly if the collection is concurrently modified.

On the other hand, fail-safe iterators don’t throw exceptions if a collection is modified while iterating over it. They operate on clones of the collection, not on the original collection. Iterators over CopyOnWriteArrayList and ConcurrentHashMap views are fail-safe.

Conclusion

The iterator pattern is a very easy pattern to understand and implement. This is why it is often thought of as a programming idiom.

In the weeks ahead, we’ll continue examining some of the more useful design patterns. Stay tuned! And don’t forget to share your comments and questions.

Leave a Comment

Your email address will not be published. Required fields are marked *

Code like a Java Guru!

Thank You

We're Excited!

Thank you for completing the form. We're excited that you have chosen to contact us about training. We will process the information as soon as we can, and we will do our best to contact you within 1 working day. (Please note that our offices are closed over weekends and public holidays.)

Don't Worry

Our privacy policy ensures your data is safe: Incus Data does not sell or otherwise distribute email addresses. We will not divulge your personal information to anyone unless specifically authorised by you.

If you need any further information, please contact us on tel: (27) 12-666-2020 or email info@incusdata.com

How can we help you?

Let us contact you about your training requirements. Just fill in a few details, and we’ll get right back to you.

Your Java tip is on its way!

Check that incusdata.com is an approved sender, so that your Java tips don’t land up in the spam folder.

Our privacy policy means your data is safe. You can unsubscribe from these tips at any time.