Project Technical Lead
Java design pattern: Iterator
Today we will look at another Java design pattern from the category of behavioral patterns Iterator. Design patterns in this category deal with the communication (interaction) between objects and their responsibility.
What is the Iterator design pattern?
The Iterator design pattern in object-oriented programming provides a way to systematically access and traverse the elements of an object stored in some container without knowing its internal representation. It also separates the algorithms applicable to the elements from the container.
What problem does the Iterator design pattern solve?
It solves the problem of efficiently accessing elements in a collection while hiding the structure of that collection. Its main goal is to provide a unified way to navigate through different types of collections without having to know their internal structure.
This pattern defines the Iterator interface, which by default contains methods such as next(), hasNext(), etc. Specific implementations of this interface are provided by classes that implement collections, such as lists, sets, arrays, and so on.
Example of Iterator implementation in Java
We’ll create a program to add notes and use the Iterator design pattern to show how we can easily access and navigate through them. We will create the interface as a template so that it can be used for any data type.
Iterator.java
package designpatterns;
// Rozhranie pre iterator
public interface Iterator<T> {
boolean hasNext();
T next();
}
The Iterator interface defines the hasNext() and next() methods. The first method should check if there is another element, the second should then return the next element.
ListIterator.java
package designpatterns;
import java.util.List;
// Konkretny iterator pre zoznam (List)
public class ListIterator<T> implements Iterator<T> {
private List<T> zoznam;
private int pozicia;
public ListIterator(List<T> zoznam) {
this.zoznam = zoznam;
this.pozicia = 0;
}
@Override
public boolean hasNext() {
return pozicia < zoznam.size();
}
@Override
public T next() {
if(this.hasNext())
return zoznam.get(pozicia++);
return null;
}
}
ListIterator implements the Iterator interface and provides a concrete implementation for List. Keeps a reference to the list (List<T>) and keeps track of the current position for the iteration. The hasNext() method checks if there is another element in the list. The next() method returns the next element in the list and moves the position to the next element.
Notes.java
package designpatterns;
import java.util.ArrayList;
import java.util.List;
public class Poznamky<T> {
private List<T> poznamky;
public Poznamky() {
this.poznamky = new ArrayList<>();
}
public void pridajPoznamku(T poznamka) {
poznamky.add(poznamka);
}
public Iterator<T> iterator() {
return new ListIterator<>(poznamky);
}
}
The Notes class stores a list of notes (of type T in this case). The addNote() method adds a new note to the list. The iterator() method creates and returns a ListIterator instance that is used to iterate over the notes in the list.
Main.java
import designpatterns.Iterator;
import designpatterns.Poznamky;
public class Main {
public static void main(String[] args) {
Poznamky<String> poznamky = new Poznamky<>();
poznamky.pridajPoznamku("Zajtra bude snežiť.");
poznamky.pridajPoznamku("Čoskoro budú Vianoce.");
poznamky.pridajPoznamku("Treba nakúpiť darčeky.");
// Pouzitie iteratora na prechadzanie cez pridane poznamky
Iterator<String> iterator = poznamky.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
Main is a client class that demonstrates the use of this design pattern. Creates a Notes instance of a particular String type, adds a few notes, and then iterates over them and prints them out using the iterator.
The output of this example is:
Summary
The Iterator design pattern is used by default to traverse a group of objects in a data structure, regardless of the specific object type. This pattern is so commonly used that there are already predefined classes in programming languages. Iterators do not have to traverse only to the next object, but they can be implemented to traverse width or depth in a tree structure, for example.
We have prepared the files with the above example in the form of code that you can run directly in Java. Download the Java Iterator code here.
If you’re a Java developer looking for work, check out our employee benefits and respond to job offers.