The Iterable and Iterator Contracts
Understand the Iterable and Iterator interfaces and how for-each loops work internally.
The Iterable and Iterator Contracts is a free Java Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Java Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Iterable and Iterator
Iterable<T> and Iterator<T> are the interfaces that power Java's for-each loop. Understanding them lets you make your own data structures loop-compatible.
The Iterable Interface
Iterable<T> has one method: iterator() that returns an Iterator<T>. Any class implementing Iterable can be used in a for-each loop.
// java.lang.Iterable<T>
interface Iterable<T> {
Iterator<T> iterator();
// default: forEach, spliterator (Java 8+)
}
// Any class implementing Iterable<T> works in for-each:
class Range implements Iterable<Integer> {
private final int start, end;
Range(int start, int end) { this.start = start; this.end = end; }
public Iterator<Integer> iterator() {
return new RangeIterator(); // defined separately
}
}The Iterator Interface
Iterator<T> has three methods: hasNext(), next(), and the optional remove().
// java.util.Iterator<T>
interface Iterator<T> {
boolean hasNext(); // true if more elements
T next(); // returns next element, advances cursor
default void remove() { throw new UnsupportedOperationException(); }
}
// How for-each desugars internally:
// for (T item : iterable) { use(item); }
// becomes:
Iterator<T> it = iterable.iterator();
while (it.hasNext()) {
T item = it.next();
// use(item)
}For-Each Loop Desugaring
The for-each loop is syntactic sugar over the Iterable/Iterator pattern. Understanding this helps you write custom Iterables correctly.
List<String> names = List.of("Alice", "Bob", "Charlie");
// For-each (readable way)
for (String name : names) {
System.out.println(name);
}
// Equivalent explicit form
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String name = it.next();
System.out.println(name);
}Iterator Cursor State
An Iterator maintains a cursor — a position in the sequence. Calling next() moves the cursor forward. Once exhausted, the iterator is not resettable.
List<Integer> nums = List.of(1, 2, 3);
Iterator<Integer> it = nums.iterator();
System.out.println(it.hasNext()); // true
System.out.println(it.next()); // 1
System.out.println(it.next()); // 2
System.out.println(it.next()); // 3
System.out.println(it.hasNext()); // false
try {
it.next(); // NoSuchElementException
} catch (java.util.NoSuchElementException e) {
System.out.println("No more elements!");
}ConcurrentModificationException
Modifying a collection while iterating with an explicit iterator (outside of Iterator.remove()) throws ConcurrentModificationException.
List<String> list = new ArrayList<>(List.of("a", "b", "c", "d"));
// BAD: modifying collection during for-each
try {
for (String s : list) {
if ("b".equals(s)) list.remove(s); // ConcurrentModificationException!
}
} catch (java.util.ConcurrentModificationException e) {
System.out.println("Cannot modify during iteration!");
}
// GOOD: use Iterator.remove()
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if ("b".equals(it.next())) it.remove(); // safe
}
System.out.println(list); // [a, c, d]Multiple Iterators
Each call to iterator() returns a fresh, independent iterator. Multiple iterators can be active simultaneously on the same collection.
List<Integer> nums = List.of(1, 2, 3);
Iterator<Integer> a = nums.iterator();
Iterator<Integer> b = nums.iterator();
System.out.println(a.next()); // 1
System.out.println(b.next()); // 1 (independent cursor)
System.out.println(a.next()); // 2
System.out.println(b.next()); // 2Iterable vs Iterator
Key distinction:
- Iterable: a source that can produce iterators — can be iterated multiple times
- Iterator: a cursor over a sequence — single-use, stateful
// Iterable: reusable
List<String> list = List.of("x", "y");
for (String s : list) {} // OK
for (String s : list) {} // OK again — new iterator each time
// Iterator: single-use
Iterator<String> it = list.iterator();
while (it.hasNext()) it.next();
// for (String s : it) {} // compile error — Iterator is not Iterable!Practical: Custom File Line Iterable
A file reader that implements Iterable to allow for-each loop over its lines.
import java.io.*;
import java.util.*;
class FileLines implements Iterable<String>, Closeable {
private final BufferedReader reader;
FileLines(String path) throws IOException {
this.reader = new BufferedReader(new FileReader(path));
}
public Iterator<String> iterator() {
return new Iterator<>() {
private String nextLine = readNext();
private String readNext() {
try { return reader.readLine(); }
catch (IOException e) { return null; }
}
public boolean hasNext() { return nextLine != null; }
public String next() {
String curr = nextLine;
nextLine = readNext();
return curr;
}
};
}
public void close() throws IOException { reader.close(); }
}forEach Default Method
Java 8 added a default forEach(Consumer) method to Iterable. This is a convenient alternative to writing explicit loops.
List<String> cities = List.of("New York", "London", "Tokyo");
// for-each loop
for (String city : cities) System.out.println(city);
// forEach with lambda
cities.forEach(city -> System.out.println(city));
// forEach with method reference (most concise)
cities.forEach(System.out::println);
// For transforming: use stream
cities.stream()
.map(String::toUpperCase)
.forEach(System.out::println);Iterator Pattern in Practice
Summary of when to implement Iterable/Iterator:
- Custom data structures (tree, graph, linked list)
- Lazy sequences that generate elements on demand
- Resource-based sequences (file lines, DB cursor, message queue)
Quick Check
What exception is thrown when you modify a collection while iterating with a for-each loop?
Recap: The Iterable and Iterator Contracts
Key takeaways:
- Iterable
has one method: iterator() — enables for-each loop support - Iterator
has hasNext(), next(), and optional remove() - For-each loop is syntactic sugar over the Iterable/Iterator pattern
- Call iterator() multiple times to get independent fresh cursors
- Never modify a collection during for-each — use Iterator.remove() instead
- Implement Iterable for custom data structures to support for-each loops
Frequently asked questions
Is the “The Iterable and Iterator Contracts” lesson free?
Yes — the full text of “The Iterable and Iterator Contracts” is free to read here on the web, and the Java Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Java Academy course, upgrade to CoddyKit PRO.
What will I learn in “The Iterable and Iterator Contracts”?
Understand the Iterable and Iterator interfaces and how for-each loops work internally. You practise Java Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Java Academy?
No prior experience is required. Java Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “The Iterable and Iterator Contracts” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Java Academy lesson?
Yes. Every Java Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- The Iterable and Iterator Contracts
- Implementing a Custom Iterator
- ListIterator and Bidirectional Traversal
- Fail-Fast vs Fail-Safe Iterators