ZetCode

Java Iterable Interface

Last modified: April 13, 2025

The java.lang.Iterable interface is a fundamental interface in Java that represents a collection of elements which can be iterated over. It's the superinterface of all collection interfaces in the Java Collections Framework. Implementing Iterable allows an object to be the target of the enhanced for-loop.

The Iterable interface provides methods to obtain an iterator over elements of a collection. It was introduced in Java 5 and enhanced in Java 8 with default methods. Understanding Iterable is crucial for working with Java collections and creating custom iterable data structures.

Iterable Interface Methods

The Iterable interface defines three methods that provide iteration capabilities. The main method is iterator, while forEach and spliterator were added as default methods in Java 8.

public interface Iterable<T> {
    Iterator<T> iterator();
    default void forEach(Consumer<? super T> action) {...}
    default Spliterator<T> spliterator() {...}
}

The code above shows the methods provided by the Iterable interface. The iterator method must be implemented, while the other two have default implementations but can be overridden for custom behavior.

Basic Iterable Implementation

This example demonstrates how to implement the Iterable interface in a custom class. We create a simple collection-like class that holds elements and provides iteration capability.

Main.java
package com.zetcode;

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

class SimpleCollection<T> implements Iterable<T> {
    private T[] elements;
    private int size;
    
    @SuppressWarnings("unchecked")
    public SimpleCollection(int capacity) {
        elements = (T[]) new Object[capacity];
        size = 0;
    }
    
    public void add(T element) {
        if (size < elements.length) {
            elements[size++] = element;
        }
    }
    
    @Override
    public Iterator<T> iterator() {
        return new Iterator<T>() {
            private int currentIndex = 0;
            
            @Override
            public boolean hasNext() {
                return currentIndex < size;
            }
            
            @Override
            public T next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }
                return elements[currentIndex++];
            }
        };
    }
}

void main() {
    SimpleCollection<String> collection = new SimpleCollection<>(3);
    collection.add("First");
    collection.add("Second");
    collection.add("Third");
    
    for (String item : collection) {
        System.out.println(item);
    }
}

In this example, we create a SimpleCollection class that implements Iterable. The class maintains an array of elements and provides an iterator implementation as an anonymous inner class. The enhanced for-loop works with our custom collection because it implements Iterable.

Using forEach Method

The forEach method, added in Java 8, performs the given action for each element of the Iterable until all elements have been processed. This method simplifies iteration with lambda expressions.

Main.java
package com.zetcode;

import java.util.Arrays;
import java.util.List;

void main() {
    List<String> languages = Arrays.asList("Java", "Python", "C++", "JavaScript");
    
    // Traditional for-loop
    System.out.println("Traditional iteration:");
    for (String lang : languages) {
        System.out.println(lang);
    }
    
    // Using forEach with lambda
    System.out.println("\nUsing forEach:");
    languages.forEach(lang -> System.out.println(lang));
    
    // Using method reference
    System.out.println("\nUsing method reference:");
    languages.forEach(System.out::println);
}

This example shows different ways to iterate over a List (which implements Iterable). The forEach method provides a concise way to process each element using a lambda expression or method reference, making the code more readable and expressive.

Custom Iterator Implementation

This example demonstrates how to create a more sophisticated custom iterator for a specialized data structure. We'll implement a range iterator that generates numbers within a specified range.

Main.java
package com.zetcode;

import java.util.Iterator;

class NumberRange implements Iterable<Integer> {
    private final int start;
    private final int end;
    private final int step;
    
    public NumberRange(int start, int end, int step) {
        this.start = start;
        this.end = end;
        this.step = step;
    }
    
    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            private int current = start;
            
            @Override
            public boolean hasNext() {
                return step > 0 ? current <= end : current >= end;
            }
            
            @Override
            public Integer next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }
                int value = current;
                current += step;
                return value;
            }
        };
    }
}

void main() {
    System.out.println("Positive step:");
    for (int num : new NumberRange(1, 10, 2)) {
        System.out.println(num);
    }
    
    System.out.println("\nNegative step:");
    for (int num : new NumberRange(10, 1, -2)) {
        System.out.println(num);
    }
}

This example creates a NumberRange class that generates numbers from start to end with a given step. The iterator handles both positive and negative steps correctly. The implementation shows how to create a stateful iterator that maintains its position during iteration.

Spliterator Example

The spliterator method returns a Spliterator over the elements described by this Iterable. Spliterators are used for parallel processing and more sophisticated traversal operations.

Main.java
package com.zetcode;

import java.util.Arrays;
import java.util.Spliterator;
import java.util.List;

void main() {
    List<String> fruits = Arrays.asList("Apple", "Banana", "Cherry", "Date", "Elderberry");
    
    // Get spliterator
    Spliterator<String> spliterator = fruits.spliterator();
    
    // Try to process elements one by one
    System.out.println("Individual elements:");
    while (spliterator.tryAdvance(System.out::println)) {}
    
    // Split and process in parallel
    System.out.println("\nSplit processing:");
    Spliterator<String> split1 = spliterator.trySplit();
    if (split1 != null) {
        System.out.println("Split1:");
        split1.forEachRemaining(System.out::println);
    }
    System.out.println("Original:");
    spliterator.forEachRemaining(System.out::println);
}

This example demonstrates basic Spliterator usage. We first process elements one by one with tryAdvance, then split the spliterator to show how it can divide work for parallel processing. Spliterators are particularly useful for parallel streams and bulk data operations.

Iterable with Primitive Types

While Iterable works with objects, we can create specialized implementations for primitive types using wrapper classes. This example shows an iterable for primitive int values.

Main.java
package com.zetcode;

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

class IntRange implements Iterable<Integer> {
    private final int[] values;
    
    public IntRange(int... values) {
        this.values = values;
    }
    
    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            private int index = 0;
            
            @Override
            public boolean hasNext() {
                return index < values.length;
            }
            
            @Override
            public Integer next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }
                return values[index++];
            }
        };
    }
}

void main() {
    IntRange range = new IntRange(10, 20, 30, 40, 50);
    
    // Using enhanced for-loop
    for (int num : range) {
        System.out.println(num);
    }
    
    // Using forEach
    System.out.println("\nUsing forEach:");
    range.forEach(num -> System.out.println(num * 2));
}

This example creates an IntRange class that holds primitive int values but provides iteration through Integer objects. The class demonstrates how to work with primitive values while still implementing the Iterable interface for use with Java's collection framework.

Nested Iterable Implementation

This example shows how to implement Iterable for a more complex data structure with nested elements. We'll create a matrix class that allows iteration through all elements row by row.

Main.java
package com.zetcode;

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

class Matrix<T> implements Iterable<T> {
    private final T[][] data;
    
    @SuppressWarnings("unchecked")
    public Matrix(int rows, int cols) {
        data = (T[][]) new Object[rows][cols];
    }
    
    public void set(int row, int col, T value) {
        data[row][col] = value;
    }
    
    @Override
    public Iterator<T> iterator() {
        return new Iterator<T>() {
            private int row = 0;
            private int col = 0;
            
            @Override
            public boolean hasNext() {
                return row < data.length && col < data[row].length;
            }
            
            @Override
            public T next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }
                
                T value = data[row][col];
                
                // Move to next element
                col++;
                if (col >= data[row].length) {
                    col = 0;
                    row++;
                }
                
                return value;
            }
        };
    }
}

void main() {
    Matrix<String> matrix = new Matrix<>(2, 3);
    matrix.set(0, 0, "A1");
    matrix.set(0, 1, "A2");
    matrix.set(0, 2, "A3");
    matrix.set(1, 0, "B1");
    matrix.set(1, 1, "B2");
    matrix.set(1, 2, "B3");
    
    System.out.println("Matrix elements:");
    for (String element : matrix) {
        System.out.println(element);
    }
}

This example implements a Matrix class that stores elements in a 2D array but provides a flat iteration through all elements. The iterator maintains its position across rows and columns, demonstrating how to handle more complex iteration scenarios while still implementing the Iterable interface.

Source

Java Iterable Interface Documentation

In this article, we've covered the Java Iterable interface with practical examples. Understanding Iterable is essential for working with Java collections and creating custom iterable data structures that work seamlessly with Java's enhanced for-loop and stream API.

Author

My name is Jan Bodnar, and I am a dedicated programmer with many years of experience in the field. I began writing programming articles in 2007 and have since authored over 1,400 articles and eight e-books. With more than eight years of teaching experience, I am committed to sharing my knowledge and helping others master programming concepts.

List all Java tutorials.