Home/Java/Iterators in Java

Iterators in Java

Learn how to traverse collections element by element

💡 Think of an Iterator like reading a book page by page - you start at the beginning, check if there are more pages (hasNext), turn to the next page (next), and sometimes you might tear out a page (remove). You can only move forward, one page at a time!

📖 What is an Iterator?

An Iterator is an object that allows you to traverse through a collection, one element at a time. It provides a uniform way to access elements of different collection types without knowing their internal structure. Think of it as a bookmark that moves through your collection!

BasicIterator.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class BasicIterator {
public static void main(String[] args) {
// Create a list
List<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
fruits.add("Mango");
System.out.println("Original list: " + fruits);
// Get an iterator
Iterator<String> iterator = fruits.iterator();
// Basic iteration pattern
System.out.println("\nIterating through list:");
while (iterator.hasNext()) { // Check if more elements exist
String fruit = iterator.next(); // Get next element
System.out.println("- " + fruit);
}
// Iterator is now exhausted - need to create new one
System.out.println("\nIterator exhausted. Creating new one...");
iterator = fruits.iterator();
// Iterate and count
int count = 0;
while (iterator.hasNext()) {
iterator.next();
count++;
}
System.out.println("Total elements: " + count);
// What happens if you call next() without hasNext()?
iterator = fruits.iterator();
try {
// Skip hasNext() checks - dangerous!
iterator.next(); // Apple
iterator.next(); // Banana
iterator.next(); // Orange
iterator.next(); // Mango
iterator.next(); // NoSuchElementException!
} catch (Exception e) {
System.out.println("\nError: " + e.getClass().getSimpleName());
System.out.println("Always use hasNext() before next()!");
}
}
}

🔍 🔄 Types of Iterators

Java provides different iterator types for different traversal needs:

1

Iterator

Basic forward-only iteration with hasNext(), next(), and remove() methods

2

ListIterator

Bidirectional iteration for Lists, can move forward and backward, add/set elements

3

Enhanced For-Loop

Simplified syntax using Iterator internally, read-only, cleaner code

4

forEach() Method

Functional approach using lambda expressions, very concise

IterationMethods.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import java.util.*;
public class IterationMethods {
public static void main(String[] args) {
List<String> languages = Arrays.asList("Java", "Python", "JavaScript", "C++", "Go");
// Method 1: Iterator (explicit)
System.out.println("1. Using Iterator:");
Iterator<String> iterator = languages.iterator();
while (iterator.hasNext()) {
System.out.println(" - " + iterator.next());
}
// Method 2: Enhanced for-loop (implicit Iterator)
System.out.println("\n2. Using Enhanced For-Loop:");
for (String lang : languages) {
System.out.println(" - " + lang);
}
// Method 3: Traditional for-loop with index (for Lists only)
System.out.println("\n3. Using Index-Based Loop:");
for (int i = 0; i < languages.size(); i++) {
System.out.println(" " + i + ": " + languages.get(i));
}
// Method 4: forEach with lambda (Java 8+)
System.out.println("\n4. Using forEach() Method:");
languages.forEach(lang -> System.out.println(" - " + lang));
// Method 5: forEach with method reference (Java 8+)
System.out.println("\n5. Using Method Reference:");
languages.forEach(System.out::println);
// Method 6: Stream API (Java 8+)
System.out.println("\n6. Using Streams:");
languages.stream()
.filter(lang -> lang.length() > 4)
.forEach(lang -> System.out.println(" - " + lang));
}
}

🗑️ Removing Elements During Iteration

RemovingWhileIterating.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import java.util.*;
public class RemovingWhileIterating {
public static void main(String[] args) {
// ===== WRONG WAY - ConcurrentModificationException =====
List<Integer> numbers1 = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
System.out.println("WRONG: Removing directly from collection");
try {
for (Integer num : numbers1) {
if (num % 2 == 0) {
numbers1.remove(num); // DANGER! Modifying during iteration
}
}
} catch (ConcurrentModificationException e) {
System.out.println("Error: " + e.getClass().getSimpleName());
System.out.println("Cannot modify collection directly during iteration!\n");
}
// ===== CORRECT WAY 1 - Using Iterator.remove() =====
List<Integer> numbers2 = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
System.out.println("CORRECT: Using Iterator.remove()");
Iterator<Integer> iterator = numbers2.iterator();
while (iterator.hasNext()) {
Integer num = iterator.next();
if (num % 2 == 0) {
iterator.remove(); // Safe removal!
}
}
System.out.println("Result: " + numbers2); // [1, 3, 5, 7, 9]
// ===== CORRECT WAY 2 - Using removeIf() =====
List<Integer> numbers3 = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
System.out.println("\nCORRECT: Using removeIf()");
numbers3.removeIf(num -> num % 2 == 0); // Remove all even numbers
System.out.println("Result: " + numbers3); // [1, 3, 5, 7, 9]
// ===== CORRECT WAY 3 - Collect to new list =====
List<Integer> numbers4 = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
System.out.println("\nCORRECT: Filtering to new list");
List<Integer> oddNumbers = new ArrayList<>();
for (Integer num : numbers4) {
if (num % 2 != 0) {
oddNumbers.add(num);
}
}
System.out.println("Result: " + oddNumbers); // [1, 3, 5, 7, 9]
// ===== Real-world example: Removing inactive users =====
List<String> users = new ArrayList<>(
Arrays.asList("active_alice", "inactive_bob", "active_charlie", "inactive_david")
);
System.out.println("\nRemoving inactive users:");
System.out.println("Before: " + users);
Iterator<String> userIterator = users.iterator();
while (userIterator.hasNext()) {
String user = userIterator.next();
if (user.startsWith("inactive_")) {
System.out.println(" Removing: " + user);
userIterator.remove();
}
}
System.out.println("After: " + users);
}
}

↔️ ListIterator: Bidirectional Traversal

ListIteratorExample.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import java.util.*;
public class ListIteratorExample {
public static void main(String[] args) {
List<String> cities = new ArrayList<>(
Arrays.asList("New York", "London", "Tokyo", "Paris", "Sydney")
);
System.out.println("Original list: " + cities);
// Get a ListIterator
ListIterator<String> listIterator = cities.listIterator();
// ===== FORWARD ITERATION =====
System.out.println("\n=== Forward Iteration ===");
while (listIterator.hasNext()) {
int index = listIterator.nextIndex();
String city = listIterator.next();
System.out.println(index + ": " + city);
}
// Now at the end of list
// ===== BACKWARD ITERATION =====
System.out.println("\n=== Backward Iteration ===");
while (listIterator.hasPrevious()) {
int index = listIterator.previousIndex();
String city = listIterator.previous();
System.out.println(index + ": " + city);
}
// ===== MODIFYING DURING ITERATION =====
System.out.println("\n=== Modifying Elements ===");
// Start fresh from beginning
listIterator = cities.listIterator();
while (listIterator.hasNext()) {
String city = listIterator.next();
// Replace "Tokyo" with "Osaka"
if (city.equals("Tokyo")) {
listIterator.set("Osaka");
System.out.println("Changed Tokyo to Osaka");
}
// Add "Berlin" after "London"
if (city.equals("London")) {
listIterator.add("Berlin");
System.out.println("Added Berlin after London");
}
}
System.out.println("\nModified list: " + cities);
// ===== STARTING FROM SPECIFIC INDEX =====
System.out.println("\n=== Starting from index 2 ===");
listIterator = cities.listIterator(2); // Start from index 2
while (listIterator.hasNext()) {
System.out.println(" - " + listIterator.next());
}
// ===== PRACTICAL EXAMPLE: Reverse a list =====
System.out.println("\n=== Reversing list ===");
List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
System.out.println("Original: " + numbers);
List<Integer> reversed = new ArrayList<>();
ListIterator<Integer> numIterator = numbers.listIterator(numbers.size());
while (numIterator.hasPrevious()) {
reversed.add(numIterator.previous());
}
System.out.println("Reversed: " + reversed);
}
}

⚠️ Understanding Fail-Fast Behavior

FailFastBehavior.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import java.util.*;
public class FailFastBehavior {
public static void main(String[] args) {
List<String> items = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));
// ===== FAIL-FAST: Throws ConcurrentModificationException =====
System.out.println("Demonstrating Fail-Fast Behavior:\n");
// Example 1: Modifying during enhanced for-loop
System.out.println("1. Modifying during enhanced for-loop:");
try {
for (String item : items) {
System.out.println(" Processing: " + item);
if (item.equals("C")) {
items.remove(item); // FAIL-FAST!
}
}
} catch (ConcurrentModificationException e) {
System.out.println(" ConcurrentModificationException thrown!\n");
}
// Example 2: Modifying with regular iterator
items = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));
System.out.println("2. Modifying collection (not iterator) during iteration:");
Iterator<String> iterator = items.iterator();
try {
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(" Processing: " + item);
if (item.equals("C")) {
items.remove(item); // FAIL-FAST! Modifying collection directly
}
}
} catch (ConcurrentModificationException e) {
System.out.println(" ConcurrentModificationException thrown!\n");
}
// ===== SAFE WAYS =====
items = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));
// Safe way 1: Use iterator.remove()
System.out.println("3. SAFE: Using iterator.remove():");
iterator = items.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(" Processing: " + item);
if (item.equals("C")) {
iterator.remove(); // SAFE!
System.out.println(" Removed C safely");
}
}
System.out.println(" Result: " + items + "\n");
// Safe way 2: Use removeIf()
items = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));
System.out.println("4. SAFE: Using removeIf():");
items.removeIf(item -> item.equals("C")); // SAFE!
System.out.println(" Result: " + items + "\n");
// Safe way 3: Copy to avoid modification issues
items = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));
System.out.println("5. SAFE: Iterating over copy:");
List<String> itemsCopy = new ArrayList<>(items);
for (String item : itemsCopy) {
System.out.println(" Processing: " + item);
if (item.equals("C")) {
items.remove(item); // SAFE! Iterating copy, modifying original
System.out.println(" Removed C safely");
}
}
System.out.println(" Result: " + items);
// ===== WHY FAIL-FAST? =====
System.out.println("\n=== Why Fail-Fast? ===");
System.out.println("Fail-fast iterators detect concurrent modifications");
System.out.println("and throw exceptions to prevent unpredictable behavior.");
System.out.println("This helps catch bugs early during development!");
}
}

⚡ Iterator vs Enhanced For-Loop

IteratorVsForLoop.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import java.util.*;
public class IteratorVsForLoop {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
numbers.add(i);
}
// ===== ITERATOR - Explicit Control =====
System.out.println("Using Iterator (explicit):");
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {
Integer num = iterator.next();
System.out.print(num + " ");
// Can remove during iteration
if (num % 3 == 0) {
iterator.remove();
}
}
System.out.println("\nAfter removal: " + numbers);
// Reset for next example
numbers.clear();
for (int i = 1; i <= 10; i++) {
numbers.add(i);
}
// ===== ENHANCED FOR-LOOP - Clean Syntax =====
System.out.println("\nUsing Enhanced For-Loop:");
for (Integer num : numbers) {
System.out.print(num + " ");
// Cannot remove here - would throw ConcurrentModificationException
}
// ===== WHEN TO USE WHICH =====
System.out.println("\n\n=== When to Use Which ===");
System.out.println("\nUse Enhanced For-Loop when:");
System.out.println(" Just reading elements");
System.out.println(" Want cleaner, more readable code");
System.out.println(" Don't need to modify collection");
System.out.println("\nUse Iterator when:");
System.out.println(" Need to remove elements");
System.out.println(" Need fine control over iteration");
System.out.println(" Iterating multiple collections in parallel");
// ===== PARALLEL ITERATION EXAMPLE =====
System.out.println("\n=== Parallel Iteration with Two Lists ===");
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<Integer> ages = Arrays.asList(25, 30, 28);
Iterator<String> nameIter = names.iterator();
Iterator<Integer> ageIter = ages.iterator();
while (nameIter.hasNext() && ageIter.hasNext()) {
System.out.println(nameIter.next() + " is " + ageIter.next() + " years old");
}
// ===== DIFFERENT COLLECTIONS =====
System.out.println("\n=== Works with All Collections ===");
// Set (no index access)
Set<String> colors = new HashSet<>(Arrays.asList("Red", "Green", "Blue"));
System.out.println("\nSet iteration:");
for (String color : colors) {
System.out.println(" - " + color);
}
// Map (special iteration)
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 87);
scores.put("Charlie", 92);
System.out.println("\nMap iteration:");
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
}
}
}

🎯 Real-World Example: Filtering and Processing

DataProcessing.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import java.util.*;
class Transaction {
String id;
double amount;
boolean approved;
public Transaction(String id, double amount) {
this.id = id;
this.amount = amount;
this.approved = false;
}
@Override
public String toString() {
return id + ": $" + amount + " (" + (approved ? "✓" : "✗") + ")";
}
}
public class DataProcessing {
public static void main(String[] args) {
// Create transaction list
List<Transaction> transactions = new ArrayList<>();
transactions.add(new Transaction("TXN001", 150.00));
transactions.add(new Transaction("TXN002", 25.50));
transactions.add(new Transaction("TXN003", 999.99));
transactions.add(new Transaction("TXN004", 10.00));
transactions.add(new Transaction("TXN005", 500.00));
System.out.println("=== Transaction Processing System ===\n");
System.out.println("All transactions:");
transactions.forEach(t -> System.out.println(" " + t));
// ===== PROCESS 1: Approve transactions over $100 =====
System.out.println("\n--- Approving transactions over $100 ---");
Iterator<Transaction> iterator = transactions.iterator();
int approvedCount = 0;
while (iterator.hasNext()) {
Transaction txn = iterator.next();
if (txn.amount > 100) {
txn.approved = true;
approvedCount++;
System.out.println("Approved: " + txn.id + " ($" + txn.amount + ")");
}
}
System.out.println("Total approved: " + approvedCount);
// ===== PROCESS 2: Remove transactions under $20 =====
System.out.println("\n--- Removing small transactions (< $20) ---");
iterator = transactions.iterator();
int removedCount = 0;
while (iterator.hasNext()) {
Transaction txn = iterator.next();
if (txn.amount < 20) {
System.out.println("Removing: " + txn.id + " ($" + txn.amount + ")");
iterator.remove();
removedCount++;
}
}
System.out.println("Total removed: " + removedCount);
// ===== PROCESS 3: Calculate total of approved transactions =====
System.out.println("\n--- Calculating totals ---");
double totalApproved = 0;
double totalPending = 0;
for (Transaction txn : transactions) {
if (txn.approved) {
totalApproved += txn.amount;
} else {
totalPending += txn.amount;
}
}
System.out.println("Total approved: $" + totalApproved);
System.out.println("Total pending: $" + totalPending);
// ===== FINAL STATE =====
System.out.println("\n=== Final Transaction List ===");
ListIterator<Transaction> listIter = transactions.listIterator();
while (listIter.hasNext()) {
int index = listIter.nextIndex();
Transaction txn = listIter.next();
System.out.println((index + 1) + ". " + txn);
}
System.out.println("\nTotal remaining: " + transactions.size());
}
}

🔑 Key Concepts

hasNext()

Checks if there are more elements to iterate

while (iterator.hasNext()) - safe way to loop

next()

Returns the next element and moves the cursor forward

Must call hasNext() first to avoid exception

remove()

Safely removes the last element returned by next()

Only way to remove during iteration without ConcurrentModificationException

Fail-Fast Behavior

Iterator detects if collection was modified during iteration

Throws ConcurrentModificationException if collection changes

Best Practices

  • Use enhanced for-loop when you just need to read elements
  • Use Iterator when you need to remove elements during iteration
  • Use ListIterator when you need bidirectional traversal or modification
  • Always call hasNext() before calling next() to avoid NoSuchElementException
  • Don't modify collection directly during iteration (use iterator.remove() instead)
  • Use forEach() with lambdas for functional-style code
  • Remember that Iterator can only be used once - create new one for re-iteration

💼 Interview Tips

  • Iterator is fail-fast - throws ConcurrentModificationException if collection modified
  • ListIterator has previousIndex(), nextIndex(), set(), and add() methods
  • Enhanced for-loop is syntactic sugar for Iterator
  • You cannot go back with regular Iterator (use ListIterator for bidirectional)
  • remove() can only be called once per call to next()
  • Understand the difference between Iterator.remove() vs Collection.remove()
  • Know that forEach() doesn't allow removing elements
  • Spliterator is for parallel processing (advanced topic)