Java Iterator Interface
A complete guide to the Java Iterator interface — hasNext, next, remove, ListIterator, fail-fast vs fail-safe iterators, ConcurrentModificationException causes and fixes, custom Iterator implementation, Iterator with List, Set, and Map, and best practices with real-world examples.
Last Updated
March 2026
Read Time
17 min
Level
Beginner to Intermediate
What is the Java Iterator Interface?
The Iterator interface (java.util.Iterator<E>) is Java's universal cursor for traversing collections. It provides a standardised, collection-agnostic way to visit every element of any Collection — whether it is an ArrayList, HashSet, LinkedList, or TreeSet — one element at a time, without knowing or caring about the collection's internal structure.
Think of an Iterator as a bookmark that moves forward through a book. You ask it: "Is there a next page?" (hasNext()) and "Give me that page" (next()). You can also "tear out the current page" (remove()). The bookmark knows nothing about whether the book is hardcover or paperback (ArrayList vs LinkedList) — it just moves forward.
Iterator was introduced in Java 1.2 as the successor to the legacy Enumeration interface. It is also the engine behind Java's for-each loop — every time you write for (String s : list), the JVM internally calls list.iterator() and uses its hasNext() and next() methods. Understanding Iterator means understanding how the for-each loop actually works.
Iterator Syntax and Methods
The Iterator interface is obtained from any Collection by calling collection.iterator(). It defines three methods — all of which are used in the classic while-loop traversal pattern.
// java.util.Iterator<E> — the full interface
public interface Iterator<E> {
// Returns true if the iteration has more elements
boolean hasNext();
// Returns the next element in the iteration
// Throws NoSuchElementException if no more elements
E next();
// Removes the last element returned by next() from the collection
// Throws IllegalStateException if next() has not been called yet
// Throws UnsupportedOperationException if remove is not supported
default void remove() {
throw new UnsupportedOperationException("remove");
}
// Java 8+ — performs action on each remaining element
default void forEachRemaining(Consumer<? super E> action) {
while (hasNext()) action.accept(next());
}
}import java.util.*;
public class IteratorIntro {
public static void main(String[] args) {
List<String> languages = new ArrayList<>();
languages.add("Java");
languages.add("Python");
languages.add("Kotlin");
languages.add("Scala");
languages.add("Groovy");
// Obtain iterator from the collection
Iterator<String> it = languages.iterator();
System.out.println("Iterating with Iterator:");
while (it.hasNext()) { // check if element exists
String lang = it.next(); // retrieve next element
System.out.println(" -> " + lang);
}
// Java 8+ — forEachRemaining
System.out.println("\nforEachRemaining:");
Iterator<String> it2 = languages.iterator();
it2.forEachRemaining(lang -> System.out.println(" ** " + lang));
}
}Output
Iterating with Iterator: -> Java -> Python -> Kotlin -> Scala -> Groovy forEachRemaining: ** Java ** Python ** Kotlin ** Scala ** GroovyWhy Use Iterator?
With for-each loops available since Java 5, beginners often ask why Iterator is still needed. Here are the concrete reasons Iterator remains essential:
- ▶
🗑️ Safe Element Removal During Traversal — This is the single most important reason. Removing elements inside a for-each loop throws ConcurrentModificationException. Iterator.remove() is the only safe way to delete elements while iterating — it removes the last element returned by next() without triggering the exception.
- ▶
🔗 Works on Any Collection — Iterator is a universal interface. The same traversal code works on ArrayList, LinkedList, HashSet, TreeSet, or any custom Collection — no type-specific code needed. This is the Iterator Design Pattern in action.
- ▶
⚡ Powers the for-each Loop Internally — The for-each loop is syntactic sugar for Iterator. Every class that implements Iterable<T> (which returns an Iterator) supports for-each. Understanding Iterator explains how for-each actually works under the hood.
- ▶
📍 Conditional Filtering and Processing — Iterator's hasNext/next gives you precise control over traversal — skip, peek, and process elements conditionally in ways that for-each syntax does not allow without awkward workarounds.
- ▶
🔄 Partial Iteration — Iterator allows stopping mid-collection. You can break out of the while loop early (e.g., after finding a match) and resume later by keeping a reference to the same iterator object.
- ▶
🏗️ Foundation for ListIterator — ListIterator extends Iterator with bidirectional traversal and modification capabilities. Understanding Iterator is the prerequisite for understanding ListIterator's more powerful feature set.
Iterator vs ListIterator vs Enumeration vs for-each
Java offers four ways to traverse a collection. Each has distinct capabilities and appropriate use cases:
Rule of thumb: Use for-each for clean read-only traversal. Use Iterator when you need to remove elements during traversal. Use ListIterator when you need to go backwards, add, or replace elements in a List. Use Enumeration only when interacting with legacy APIs (Properties, Vector) that require it.
Iterator in the Java Collections Hierarchy
Iterator sits at the intersection of two key hierarchies — the Iterator interface hierarchy and the Iterable interface that every Collection implements.
Key design insight: Iterable is the capability interface — it says "I can produce an Iterator". Iterator is the cursor itself. A class implementing Iterable enables for-each support. A class implementing Iterator defines how traversal happens. These two roles are deliberately separated so a collection can produce multiple independent iterators simultaneously.
Iterator and ListIterator Methods — Complete Reference
Here is the complete method reference for both Iterator and ListIterator, including the default methods added in Java 8:
Iterator with List, Set, and Map
Iterator works uniformly across all Collection types. Here is a comprehensive demo of Iterator with ArrayList, HashSet, and HashMap — including safe removal.
import java.util.*;
public class IteratorWithList {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>(
Arrays.asList(10, 25, 3, 47, 8, 62, 15, 91, 4, 33));
System.out.println("Original : " + numbers);
// Remove all odd numbers using Iterator.remove()
Iterator<Integer> it = numbers.iterator();
while (it.hasNext()) {
int n = it.next();
if (n % 2 != 0) {
it.remove(); // safe — no ConcurrentModificationException
}
}
System.out.println("Evens only: " + numbers);
// Partial traversal — stop after finding first element > 20
List<Integer> scores = new ArrayList<>(
Arrays.asList(5, 18, 33, 72, 11, 90));
Iterator<Integer> it2 = scores.iterator();
while (it2.hasNext()) {
int s = it2.next();
if (s > 20) {
System.out.println("First score > 20: " + s);
break; // stop mid-collection
}
}
}
}Output
Original : [10, 25, 3, 47, 8, 62, 15, 91, 4, 33] Evens only: [10, 8, 62, 4] First score > 20: 33import java.util.*;
public class IteratorSetMap {
public static void main(String[] args) {
// --- Iterator with HashSet ---
Set<String> cities = new HashSet<>(
Arrays.asList("Delhi", "Mumbai", "Pune", "Hyderabad", "Chennai"));
System.out.println("Cities Set:");
Iterator<String> setIt = cities.iterator();
while (setIt.hasNext()) {
System.out.print(" " + setIt.next());
}
// Remove cities with length < 5
setIt = cities.iterator();
while (setIt.hasNext()) {
if (setIt.next().length() < 5) setIt.remove();
}
System.out.println("\nAfter removing short names: " + cities);
// --- Iterator with Map (via entrySet) ---
Map<String, Integer> stock = new LinkedHashMap<>();
stock.put("Apples", 50);
stock.put("Bananas", 0);
stock.put("Mangoes", 30);
stock.put("Grapes", 0);
stock.put("Oranges", 15);
System.out.println("\nOriginal stock: " + stock);
// Remove out-of-stock items using Iterator on entrySet
Iterator<Map.Entry<String, Integer>> mapIt = stock.entrySet().iterator();
while (mapIt.hasNext()) {
Map.Entry<String, Integer> entry = mapIt.next();
if (entry.getValue() == 0) {
mapIt.remove(); // safe removal from map via iterator
}
}
System.out.println("In-stock only: " + stock);
}
}Output
Cities Set: Chennai Delhi Pune Mumbai Hyderabad After removing short names: [Delhi, Mumbai, Chennai, Hyderabad] Original stock: {Apples=50, Bananas=0, Mangoes=30, Grapes=0, Oranges=15} In-stock only: {Apples=50, Mangoes=30, Oranges=15}ListIterator — Bidirectional Traversal and Modification
ListIterator extends Iterator with six additional methods that enable backward traversal, in-place replacement, and element insertion during iteration. It is only available on List implementations (ArrayList, LinkedList).
import java.util.*;
public class ListIteratorDemo {
public static void main(String[] args) {
List<String> days = new ArrayList<>(
Arrays.asList("Monday", "Tuesday", "Wednesday", "Thursday", "Friday"));
// --- Forward traversal with index ---
System.out.println("Forward traversal:");
ListIterator<String> lit = days.listIterator();
while (lit.hasNext()) {
System.out.println(" [" + lit.nextIndex() + "] " + lit.next());
}
// --- Backward traversal ---
System.out.println("\nBackward traversal:");
while (lit.hasPrevious()) {
System.out.println(" [" + lit.previousIndex() + "] " + lit.previous());
}
// --- set() — replace elements in place ---
System.out.println("\nReplace weekdays with short names:");
ListIterator<String> setLit = days.listIterator();
while (setLit.hasNext()) {
String day = setLit.next();
setLit.set(day.substring(0, 3).toUpperCase()); // Mon, Tue ...
}
System.out.println(" " + days);
// --- add() — insert between elements ---
System.out.println("\nInsert '--' between each day:");
List<String> spaced = new ArrayList<>(days);
ListIterator<String> addLit = spaced.listIterator();
boolean first = true;
while (addLit.hasNext()) {
addLit.next();
if (!first) { addLit.previous(); addLit.add("--"); addLit.next(); }
first = false;
}
System.out.println(" " + spaced);
// --- start from specific index ---
System.out.println("\nStart from index 2:");
ListIterator<String> fromIdx = days.listIterator(2);
while (fromIdx.hasNext()) {
System.out.print(" " + fromIdx.next());
}
}
}Output
Forward traversal: [0] Monday [1] Tuesday [2] Wednesday [3] Thursday [4] Friday Backward traversal: [4] Friday [3] Thursday [2] Wednesday [1] Tuesday [0] Monday Replace weekdays with short names: [MON, TUE, WED, THU, FRI] Insert '--' between each day: [MON, --, TUE, --, WED, --, THU, --, FRI] Start from index 2: WED THU FRIFail-Fast vs Fail-Safe Iterators
One of the most important and interview-critical concepts around iterators is the difference between fail-fast and fail-safe behaviour. This determines what happens when a collection is modified while its iterator is active.
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class FailFastVsFailSafe {
public static void main(String[] args) {
// --- FAIL-FAST: ArrayList Iterator ---
System.out.println("--- Fail-Fast (ArrayList) ---");
List<String> failFastList = new ArrayList<>(
Arrays.asList("Alpha", "Beta", "Gamma", "Delta"));
Iterator<String> ffIt = failFastList.iterator();
try {
while (ffIt.hasNext()) {
String s = ffIt.next();
System.out.println(" Read: " + s);
if (s.equals("Beta")) {
failFastList.add("Epsilon"); // direct modification!
}
}
} catch (ConcurrentModificationException e) {
System.out.println(" ConcurrentModificationException caught!");
}
// --- FAIL-SAFE: CopyOnWriteArrayList Iterator ---
System.out.println("\n--- Fail-Safe (CopyOnWriteArrayList) ---");
List<String> failSafeList = new CopyOnWriteArrayList<>(
Arrays.asList("Alpha", "Beta", "Gamma", "Delta"));
Iterator<String> fsIt = failSafeList.iterator();
while (fsIt.hasNext()) {
String s = fsIt.next();
System.out.println(" Read: " + s);
if (s.equals("Beta")) {
failSafeList.add("Epsilon"); // modification allowed — no exception
}
}
// 'Epsilon' was added but NOT seen by the iterator (snapshot)
System.out.println(" List after iteration: " + failSafeList);
}
}Output
--- Fail-Fast (ArrayList) --- Read: Alpha Read: Beta ConcurrentModificationException caught! --- Fail-Safe (CopyOnWriteArrayList) --- Read: Alpha Read: Beta Read: Gamma Read: Delta List after iteration: [Alpha, Beta, Gamma, Delta, Epsilon]Iterator Execution Flow — Flowchart
The flowchart below shows the complete lifecycle of an Iterator — from obtaining it, through traversal and safe removal, to exhaustion.
Code Execution Flow — from source to output
ConcurrentModificationException — Causes and All Fixes
ConcurrentModificationException is one of the most common runtime errors Java developers encounter. Understanding exactly when it occurs and all the ways to fix it is an essential production skill.
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
public class CMEFixDemo {
public static void main(String[] args) {
List<String> names = new ArrayList<>(
Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve"));
// ❌ CAUSE 1: remove() inside for-each loop
// for (String n : names) { if (n.startsWith("C")) names.remove(n); }
// → ConcurrentModificationException
// ✅ FIX 1: Use Iterator.remove()
List<String> fix1 = new ArrayList<>(names);
Iterator<String> it = fix1.iterator();
while (it.hasNext()) {
if (it.next().startsWith("C")) it.remove();
}
System.out.println("Fix 1 (Iterator.remove): " + fix1);
// ✅ FIX 2: removeIf (Java 8+) — cleanest
List<String> fix2 = new ArrayList<>(names);
fix2.removeIf(n -> n.startsWith("C"));
System.out.println("Fix 2 (removeIf) : " + fix2);
// ✅ FIX 3: Collect to new list via Stream, then reassign
List<String> fix3 = names.stream()
.filter(n -> !n.startsWith("C"))
.collect(Collectors.toList());
System.out.println("Fix 3 (Stream.filter) : " + fix3);
// ✅ FIX 4: Collect indices/elements to remove, bulk remove after loop
List<String> fix4 = new ArrayList<>(names);
List<String> toRemove = new ArrayList<>();
for (String n : fix4) {
if (n.startsWith("C")) toRemove.add(n);
}
fix4.removeAll(toRemove);
System.out.println("Fix 4 (removeAll) : " + fix4);
// ✅ FIX 5: CopyOnWriteArrayList — for concurrent / multi-threaded
List<String> fix5 = new CopyOnWriteArrayList<>(names);
for (String n : fix5) {
if (n.startsWith("C")) fix5.remove(n); // safe — no CME
}
System.out.println("Fix 5 (COWAL) : " + fix5);
}
}Output
Fix 1 (Iterator.remove): [Alice, Bob, David, Eve] Fix 2 (removeIf) : [Alice, Bob, David, Eve] Fix 3 (Stream.filter) : [Alice, Bob, David, Eve] Fix 4 (removeAll) : [Alice, Bob, David, Eve] Fix 5 (COWAL) : [Alice, Bob, David, Eve]Implementing Custom Iterator and Iterable
You can make any custom class support for-each loops by implementing Iterable<T> and returning a custom Iterator<T>. This is the Iterator Design Pattern — it decouples traversal logic from the data structure.
import java.util.Iterator;
import java.util.NoSuchElementException;
// Custom Iterable class — a range of integers [start, end]
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 RangeIterator();
}
// Private inner class — the actual Iterator implementation
private class RangeIterator implements 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(
"No more elements in range [" + start + ", " + end + "]");
}
int val = current;
current += step;
return val;
}
}
}
public class CustomIteratorDemo {
public static void main(String[] args) {
// for-each works because NumberRange implements Iterable
System.out.print("Range 1-10 step 1 : ");
for (int n : new NumberRange(1, 10, 1)) {
System.out.print(n + " ");
}
System.out.print("\nRange 0-20 step 5 : ");
for (int n : new NumberRange(0, 20, 5)) {
System.out.print(n + " ");
}
System.out.print("\nRange 10-1 step -2 : ");
for (int n : new NumberRange(10, 1, -2)) {
System.out.print(n + " ");
}
// Multiple independent iterators from same object
NumberRange evens = new NumberRange(2, 10, 2);
Iterator<Integer> it1 = evens.iterator();
Iterator<Integer> it2 = evens.iterator();
System.out.println("\nit1.next(): " + it1.next()); // 2
System.out.println("it2.next(): " + it2.next()); // 2 — independent!
System.out.println("it1.next(): " + it1.next()); // 4
}
}Output
Range 1-10 step 1 : 1 2 3 4 5 6 7 8 9 10 Range 0-20 step 5 : 0 5 10 15 20 Range 10-1 step -2 : 10 8 6 4 2 it1.next(): 2 it2.next(): 2 it1.next(): 4Best Practices for Using Iterator
Following these best practices will prevent the most common Iterator bugs and keep your traversal code clean, correct, and maintainable:
- ▶
✅ 1. Always Use Iterator.remove() — Never Direct Collection.remove() Inside a Loop — Calling list.remove(element) or map.remove(key) directly inside a for-each or Iterator while loop causes ConcurrentModificationException. Always use it.remove() for safe deletion during traversal. For bulk conditional removal, prefer list.removeIf(predicate) which is cleaner and internally uses an Iterator.
- ▶
✅ 2. Call next() Before remove() — iterator.remove() removes the last element returned by next(). Calling remove() before any next() call, or calling it twice consecutively without an intervening next(), throws IllegalStateException. Always follow the pattern: if (it.hasNext()) { E e = it.next(); if (condition) it.remove(); }.
- ▶
✅ 3. Check hasNext() Before Every next() Call — Calling next() on an exhausted iterator (hasNext() == false) throws NoSuchElementException. Always guard every next() call with a preceding hasNext() check — this is why the while (it.hasNext()) pattern is the canonical Iterator usage.
- ▶
✅ 4. Use for-each When You Do Not Need to Remove — For simple read-only traversal, for-each is cleaner, less error-prone, and equally performant. Reserve explicit Iterator usage for scenarios requiring removal, partial traversal, or concurrent access patterns.
- ▶
✅ 5. Use ListIterator for In-Place Modification of Lists — When you need to replace elements during traversal (e.g., normalize all strings to uppercase), ListIterator.set(E e) is the correct tool. Avoid index-based set() inside a for-each loop — it works but is error-prone and obscures intent.
- ▶
✅ 6. Use removeIf() as the Modern Alternative — For Java 8+, list.removeIf(predicate) is the cleanest way to conditionally remove elements without explicit Iterator handling. It is internally implemented with an Iterator, but gives you a declarative, readable one-liner.
- ▶
✅ 7. Implement Both Iterable and Iterator Correctly in Custom Classes — When implementing a custom Iterable, ensure that each call to iterator() returns a fresh, independent Iterator object with its own state. Never return the same Iterator object — that would mean only one traversal can be active at a time.
- ▶
❌ 8. Do Not Share Iterator Objects Between Threads — Iterator objects are not thread-safe. Even for thread-safe collections like ConcurrentHashMap, the iterator itself must not be shared across threads. Each thread should obtain its own iterator from the collection.
Real-World Code Examples
Example 1 — Shopping Cart Filter with Iterator
import java.util.*;
class CartItem {
String name;
double price;
boolean inStock;
CartItem(String name, double price, boolean inStock) {
this.name = name;
this.price = price;
this.inStock = inStock;
}
@Override public String toString() {
return name + "(₹" + price + ", " + (inStock ? "✅" : "❌") + ")";
}
}
public class CartFilter {
public static void main(String[] args) {
List<CartItem> cart = new ArrayList<>(Arrays.asList(
new CartItem("Laptop", 75000, true),
new CartItem("Headphones", 2500, true),
new CartItem("USB Hub", 850, false),
new CartItem("Webcam", 3200, true),
new CartItem("Mouse Pad", 450, false),
new CartItem("Keyboard", 1800, true)
));
System.out.println("Before filter: " + cart);
// Remove out-of-stock items using Iterator
Iterator<CartItem> it = cart.iterator();
while (it.hasNext()) {
if (!it.next().inStock) it.remove();
}
System.out.println("\nIn-stock items:");
cart.forEach(item -> System.out.printf(" %-15s ₹%.0f%n", item.name, item.price));
// Calculate total using Iterator
double total = 0;
Iterator<CartItem> totalIt = cart.iterator();
while (totalIt.hasNext()) total += totalIt.next().price;
System.out.printf("%nCart Total: ₹%.0f%n", total);
}
}Output
Before filter: [Laptop(₹75000.0, ✅), Headphones(₹2500.0, ✅), USB Hub(₹850.0, ❌), Webcam(₹3200.0, ✅), Mouse Pad(₹450.0, ❌), Keyboard(₹1800.0, ✅)] In-stock items: Laptop ₹75000 Headphones ₹2500 Webcam ₹3200 Keyboard ₹1800 Cart Total: ₹84500Example 2 — Text Processor with ListIterator
import java.util.*;
public class TextNormalizer {
public static void main(String[] args) {
List<String> tokens = new ArrayList<>(Arrays.asList(
" Hello ", "WORLD", "", "java", " Iterator ",
"null", "PATTERN", " ", "design"
));
System.out.println("Raw tokens: " + tokens);
ListIterator<String> lit = tokens.listIterator();
while (lit.hasNext()) {
String token = lit.next();
String trimmed = token.trim();
if (trimmed.isEmpty() || trimmed.equals("null")) {
lit.remove(); // remove blank/null tokens
} else {
// Normalize: trim + title case
String normalized = trimmed.substring(0, 1).toUpperCase()
+ trimmed.substring(1).toLowerCase();
lit.set(normalized); // replace in place
}
}
System.out.println("Normalized : " + tokens);
// Reverse the cleaned list using ListIterator
System.out.print("Reversed : ");
ListIterator<String> rev = tokens.listIterator(tokens.size());
while (rev.hasPrevious()) {
System.out.print(rev.previous() + " ");
}
}
}Output
Raw tokens: [ Hello , WORLD, , java, Iterator , null, PATTERN, , design] Normalized : [Hello, World, Java, Iterator, Pattern, Design] Reversed : Design Pattern Iterator Java World HelloPractice This Code — Live Editor
Advantages and Disadvantages of Iterator
Iterator is a well-designed interface that solves specific traversal problems cleanly — but it comes with its own set of constraints. Knowing both sides makes you a more effective Java developer.
Java Iterator — Interview Questions
These are the most frequently asked interview questions on the Java Iterator interface for Java developer and backend engineer positions.
Practice Questions — Test Your Knowledge
Test your understanding of Java Iterator with these practice questions. Attempt each before revealing the answer.
1. What is the output? List<String> list = new ArrayList<>(Arrays.asList("A","B","C","D")); Iterator<String> it = list.iterator(); it.next(); it.next(); it.remove(); System.out.println(list);
Easy2. Why does this code throw ConcurrentModificationException and what is the fix? for (String s : list) { if (s.equals("B")) list.remove(s); }
Easy3. What is the output? List<Integer> nums = new ArrayList<>(Arrays.asList(1,2,3,4,5)); ListIterator<Integer> lit = nums.listIterator(nums.size()); while (lit.hasPrevious()) { System.out.print(lit.previous() + " "); }
Easy4. What exception does it.next() throw when the iterator is exhausted, and why?
Easy5. You have a List<String> and want to normalize each element (trim + capitalize). Which iteration method is correct: Iterator, ListIterator, or for-each? Why?
Medium6. What is the difference between how CopyOnWriteArrayList and ArrayList handle concurrent modification during iteration?
Medium7. What happens when you call it.remove() before calling it.next()? Iterator<String> it = list.iterator(); it.remove(); // called without prior next()
Medium8. Implement a class EvenNumbers that is Iterable<Integer> and produces all even numbers from 2 to N inclusive. Show its usage with for-each.
HardConclusion — Mastering Java Iterator
The Iterator interface is deceptively simple — just three methods — yet it underpins every collection traversal in Java. It powers the for-each loop, defines the boundary between the Iterator Design Pattern's traversal logic and data structure, and solves the critical problem of safe element removal during iteration that trips up beginners and produces production bugs.
Mastering Iterator means understanding when to use it over for-each (when removal or partial traversal is needed), knowing its relationship with ListIterator (for in-place modification and backward traversal), understanding the fail-fast mechanism behind ConcurrentModificationException (and all five ways to fix it), and being able to implement custom Iterable classes for domain objects.
Your next steps: explore Spliterator (Java 8) — the parallel-capable successor to Iterator used by the Stream API; study how Java 21's virtual threads interact with fail-safe iterators in concurrent workloads; and understand how Stream.iterate() and Stream.generate() provide infinite lazy sequences built on the same cursor concept as Iterator.
Remember: for-each for reading, Iterator.remove() for safe deletion, ListIterator.set() for replacement, removeIf() for clean bulk deletion, and always guard next() with hasNext(). These five habits will keep your collection traversal code correct, expressive, and production-ready. ☕