Java > Design Patterns in Java > Behavioral Patterns > Iterator Pattern

External Iterator Example

This snippet illustrates an external iterator, explicitly managed by the client code. The `WordIterator` allows you to traverse the words in a given sentence.

Word Iterator

The `WordIterator` class splits the given sentence into words and then iterates through them using the `hasNext()` and `next()` methods. The `Sentence` class acts as the aggregate and provides the `getIterator()` method to obtain the `WordIterator` instance. The main method then uses this iterator to print each word in the sentence. This differs from a Java Collection Library Iterator which would normally be returned from the Collection implementation class.

import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;

class WordIterator implements Iterator<String> {
    private String[] words;
    private int index = 0;

    public WordIterator(String sentence) {
        this.words = sentence.split(" ");
    }

    @Override
    public boolean hasNext() {
        return index < words.length;
    }

    @Override
    public String next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }
        return words[index++];
    }
}

class Sentence {
    private String sentence;

    public Sentence(String sentence) {
        this.sentence = sentence;
    }

    public WordIterator getIterator() {
        return new WordIterator(sentence);
    }
}

public class ExternalIteratorDemo {
    public static void main(String[] args) {
        Sentence sentence = new Sentence("This is a sample sentence");
        WordIterator iterator = sentence.getIterator();

        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

Concepts Demonstrated

This example showcases the core components of the Iterator pattern: the iterator interface (`Iterator`), the concrete iterator (`WordIterator`), and the aggregate (`Sentence`). The client code explicitly manages the iterator's lifecycle.

Iterator in Java Collection

Explanation: This code demonstrates how to use the Iterator provided by the Java Collection Framework. We create an ArrayList of names and obtain an Iterator from it. We then use the hasNext() and next() methods to traverse the list and print each name. This is a common use case of the Iterator pattern in Java.

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class CollectionIterator {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("Alice");
        names.add("Bob");
        names.add("Charlie");

        // Using iterator to traverse the list
        Iterator<String> iterator = names.iterator();

        while (iterator.hasNext()) {
            String name = iterator.next();
            System.out.println(name);
        }
    }
}

When to Use

Use this external iterator pattern when you need fine-grained control over the iteration process or when you need to customize the iteration behavior. This is useful when iterating over data structures that do not implement the Collection interface.

Pros

  • Greater flexibility in controlling the iteration process.
  • Allows for custom iteration behavior tailored to specific needs.

Cons

  • More complex to implement compared to using built-in iterators.
  • The client code is responsible for managing the iterator's lifecycle.

FAQ

  • What happens if the sentence is empty?

    If the sentence is empty, the `words` array will be empty, and `hasNext()` will immediately return `false`. `next()` will throw `NoSuchElementException` if called on an empty iterator.
  • Is the `WordIterator` thread-safe?

    No, the `WordIterator` is not thread-safe. If multiple threads access and modify the underlying sentence or the iterator's state concurrently, it can lead to unexpected behavior. Thread-safe iterators require synchronization mechanisms.