Java Iterator
Universal way to traverse collections safely and efficiently
🔄 What is Iterator?
Iterator is a Java interface that provides a universal way to traverse collections. It allows safe element removal during iteration and works with all collection types consistently.
// Simple Iterator example
List<String> fruits = Arrays.asList("Apple", "Banana", "Cherry");
Iterator<String> it = fruits.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
Iterator Key Features
Universal Traversal
Works with all collection types
List<String> list = new ArrayList<>();
Set<String> set = new HashSet<>();
// Both use same iterator pattern
Iterator<String> listIt = list.iterator();
Iterator<String> setIt = set.iterator();
Safe Removal
Remove elements safely during iteration
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String item = it.next();
if (item.equals("remove")) {
it.remove(); // Safe removal
}
}
Fail-Fast
Detects concurrent modifications
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String item = it.next();
// list.add("new"); // ConcurrentModificationException
it.remove(); // This is safe
}
Forward-Only
One-way traversal from start to end
Iterator<String> it = list.iterator();
// Can only move forward
while (it.hasNext()) {
String current = it.next();
// No previous() method in basic Iterator
}
🔹 Basic Iterator Usage
Essential Iterator operations and patterns:
import java.util.*;
public class IteratorExample {
public static void main(String[] args) {
// Create a list with some data
List<String> languages = new ArrayList<>();
languages.add("Java");
languages.add("Python");
languages.add("JavaScript");
languages.add("C++");
languages.add("Go");
// Basic iteration
System.out.println("All languages:");
Iterator<String> iterator = languages.iterator();
while (iterator.hasNext()) {
String language = iterator.next();
System.out.println("- " + language);
}
// Iteration with conditional removal
System.out.println("\nRemoving languages with '+' in name:");
iterator = languages.iterator(); // Get fresh iterator
while (iterator.hasNext()) {
String language = iterator.next();
if (language.contains("+")) {
System.out.println("Removing: " + language);
iterator.remove(); // Safe removal during iteration
}
}
System.out.println("\nRemaining languages: " + languages);
// Enhanced for-loop (uses iterator internally)
System.out.println("\nUsing enhanced for-loop:");
for (String language : languages) {
System.out.println("* " + language);
}
}
}
Output:
All languages:
- Java
- Python
- JavaScript
- C++
- Go
Removing languages with '+' in name:
Removing: C++
Remaining languages: [Java, Python, JavaScript, Go]
Using enhanced for-loop:
* Java
* Python
* JavaScript
* Go
🔹 Iterator with Different Collections
Using Iterator with various collection types:
// ArrayList Iterator
List<Integer> arrayList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
System.out.println("ArrayList iteration:");
Iterator<Integer> listIt = arrayList.iterator();
while (listIt.hasNext()) {
Integer num = listIt.next();
if (num % 2 == 0) {
listIt.remove(); // Remove even numbers
} else {
System.out.println("Odd number: " + num);
}
}
System.out.println("ArrayList after removal: " + arrayList);
// HashSet Iterator
Set<String> hashSet = new HashSet<>(Arrays.asList("Apple", "Banana", "Cherry", "Date"));
System.out.println("\nHashSet iteration:");
Iterator<String> setIt = hashSet.iterator();
while (setIt.hasNext()) {
String fruit = setIt.next();
System.out.println("Fruit: " + fruit);
if (fruit.startsWith("B")) {
setIt.remove(); // Remove fruits starting with 'B'
}
}
System.out.println("HashSet after removal: " + hashSet);
// TreeMap Iterator (for keys)
TreeMap<String, Integer> treeMap = new TreeMap<>();
treeMap.put("Charlie", 25);
treeMap.put("Alice", 30);
treeMap.put("Bob", 22);
System.out.println("\nTreeMap key iteration (sorted):");
Iterator<String> keyIt = treeMap.keySet().iterator();
while (keyIt.hasNext()) {
String name = keyIt.next();
Integer age = treeMap.get(name);
System.out.println(name + " is " + age + " years old");
}
// TreeMap entry iteration
System.out.println("\nTreeMap entry iteration:");
Iterator<Map.Entry<String, Integer>> entryIt = treeMap.entrySet().iterator();
while (entryIt.hasNext()) {
Map.Entry<String, Integer> entry = entryIt.next();
if (entry.getValue() < 25) {
System.out.println("Removing young person: " + entry.getKey());
entryIt.remove();
}
}
System.out.println("TreeMap after removal: " + treeMap);
Output:
ArrayList iteration:
Odd number: 1
Odd number: 3
Odd number: 5
ArrayList after removal: [1, 3, 5]
HashSet iteration:
Fruit: Apple
Fruit: Cherry
Fruit: Date
Fruit: Banana
HashSet after removal: [Apple, Cherry, Date]
TreeMap key iteration (sorted):
Alice is 30 years old
Bob is 22 years old
Charlie is 25 years old
🔹 ListIterator - Bidirectional Iterator
ListIterator provides additional functionality for Lists:
List<String> cities = new ArrayList<>(Arrays.asList("New York", "London", "Tokyo", "Paris"));
// ListIterator allows bidirectional traversal
ListIterator<String> listIterator = cities.listIterator();
System.out.println("Forward iteration:");
while (listIterator.hasNext()) {
int index = listIterator.nextIndex();
String city = listIterator.next();
System.out.println(index + ": " + city);
// Add element after specific city
if (city.equals("London")) {
listIterator.add("Berlin"); // Insert after London
}
// Replace specific city
if (city.equals("Tokyo")) {
listIterator.set("Kyoto"); // Replace Tokyo with Kyoto
}
}
System.out.println("\nList after modifications: " + cities);
System.out.println("\nBackward iteration:");
while (listIterator.hasPrevious()) {
int index = listIterator.previousIndex();
String city = listIterator.previous();
System.out.println(index + ": " + city);
}
// Start from specific position
System.out.println("\nIteration starting from index 2:");
ListIterator<String> positionIterator = cities.listIterator(2);
while (positionIterator.hasNext()) {
String city = positionIterator.next();
System.out.println("From position 2: " + city);
}
// Demonstrate ListIterator methods
List<Integer> numbers = new ArrayList<>(Arrays.asList(10, 20, 30));
ListIterator<Integer> numIt = numbers.listIterator();
System.out.println("\nListIterator methods demonstration:");
System.out.println("Original: " + numbers);
// Add at beginning
numIt.add(5);
System.out.println("After adding 5 at start: " + numbers);
// Move to next and replace
numIt.next(); // Skip 5
numIt.set(15); // Replace 10 with 15
System.out.println("After replacing 10 with 15: " + numbers);
// Add between elements
numIt.next(); // Move to 20
numIt.add(25); // Add 25 before 20
System.out.println("After adding 25: " + numbers);
Output:
Forward iteration:
0: New York
1: London
3: Tokyo
5: Paris
List after modifications: [New York, London, Berlin, Kyoto, Paris]
Backward iteration:
4: Paris
3: Kyoto
2: Berlin
1: London
0: New York
ListIterator methods demonstration:
Original: [10, 20, 30]
After adding 5 at start: [5, 10, 20, 30]
After replacing 10 with 15: [5, 15, 20, 30]
After adding 25: [5, 15, 25, 20, 30]
🔹 Iterator Best Practices
Common patterns and best practices for using Iterator:
// 1. Always check hasNext() before calling next()
List<String> items = Arrays.asList("A", "B", "C");
Iterator<String> it = items.iterator();
while (it.hasNext()) { // Always check first
String item = it.next(); // Then get next
System.out.println(item);
}
// 2. Use try-with-resources for custom iterators (if they implement AutoCloseable)
// Most built-in iterators don't need this, but custom ones might
// 3. Avoid ConcurrentModificationException
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D"));
Iterator<String> iterator = list.iterator();
// WRONG - Don't modify collection directly during iteration
// while (iterator.hasNext()) {
// String item = iterator.next();
// if (item.equals("B")) {
// list.remove(item); // ConcurrentModificationException!
// }
// }
// RIGHT - Use iterator.remove()
iterator = list.iterator(); // Get fresh iterator
while (iterator.hasNext()) {
String item = iterator.next();
if (item.equals("B")) {
iterator.remove(); // Safe removal
}
}
System.out.println("After safe removal: " + list);
// 4. Iterator vs Enhanced For-Loop
System.out.println("\nComparison of iteration methods:");
// Enhanced for-loop (cleaner for simple iteration)
for (String item : list) {
System.out.println("Enhanced for: " + item);
}
// Iterator (better when you need to remove elements)
iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println("Iterator: " + item);
// Can call iterator.remove() here if needed
}
// 5. Custom Iterator example
class NumberRange implements Iterable<Integer> {
private int start, end;
NumberRange(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
private int current = start;
@Override
public boolean hasNext() {
return current <= end;
}
@Override
public Integer next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return current++;
}
};
}
}
// Use custom iterator
System.out.println("\nCustom iterator (range 1-5):");
NumberRange range = new NumberRange(1, 5);
for (Integer num : range) {
System.out.println("Number: " + num);
}
Output:
A
B
C
After safe removal: [A, C, D]
Comparison of iteration methods:
Enhanced for: A
Enhanced for: C
Enhanced for: D
Iterator: A
Iterator: C
Iterator: D
Custom iterator (range 1-5):
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5