Collection Iteration
“Iteration is fundamental to working with collections. Understanding the different iteration mechanisms and their trade-offs is essential for writing efficient and maintainable code.”
Overview
Section titled “Overview”Collection iteration is the process of accessing and processing each element in a collection sequentially. Java provides multiple iteration mechanisms, each with specific use cases, performance characteristics, and capabilities.
Evolution of Iteration in Java
Section titled “Evolution of Iteration in Java”- Traditional loops: Index-based iteration (for arrays and lists)
- Iterator pattern: Generic iteration for all collections
- Enhanced for-loop: Simplified syntax for Iterables
- Stream API: Functional programming approach
- forEach method: Imperative style with lambdas
Iterable and Iterator Hierarchy
Section titled “Iterable and Iterator Hierarchy”Interface Relationships
Section titled “Interface Relationships”Iterable<T> (interface)├── Collection<T> (interface)│ ├── List<T>, Set<T>, Queue<T>...│ └── All collection implementations├── Map<K,V> (not directly iterable)│ └── entrySet(), keySet(), values() return iterables└── Custom iterable classes
Iterator<T> (interface)├── ListIterator<T> (interface) - Bidirectional iteration├── Spliterator<T> (interface) - Parallel iteration support└── Various implementation classesThe Iterable Interface
Section titled “The Iterable Interface”Basic Iterable Usage
Section titled “Basic Iterable Usage”public class IterableExample { public void demonstrateIterable() { List<String> fruits = Arrays.asList("apple", "banana", "cherry");
// Using iterator() method Iterator<String> iterator = fruits.iterator(); while (iterator.hasNext()) { String fruit = iterator.next(); System.out.println(fruit); }
// Using enhanced for-loop (syntax sugar for iterator) for (String fruit : fruits) { System.out.println(fruit); }
// Using forEach method (Java 8+) fruits.forEach(System.out::println); }}Iterator Best Practices
Section titled “Iterator Best Practices”public class IteratorBestPractices {
// ✅ Good - Safe element removal during iteration public void removeEvenNumbers(List<Integer> numbers) { Iterator<Integer> iterator = numbers.iterator(); while (iterator.hasNext()) { Integer number = iterator.next(); if (number % 2 == 0) { iterator.remove(); // Safe removal } } }
// ❌ Bad - ConcurrentModificationException risk public void removeEvenNumbersBad(List<Integer> numbers) { for (Integer number : numbers) { if (number % 2 == 0) { numbers.remove(number); // Throws exception! } } }
// ✅ Good - Check hasNext() before next() public void safeIteration(Collection<String> items) { Iterator<String> iterator = items.iterator(); while (iterator.hasNext()) { String item = iterator.next(); processItem(item); } }}ListIterator for Bidirectional Iteration
Section titled “ListIterator for Bidirectional Iteration”ListIterator extends Iterator and provides bidirectional iteration capabilities for List implementations.
public class ListIteratorExample { public void demonstrateListIterator() { List<String> items = new ArrayList<>(Arrays.asList("a", "b", "c", "d")); ListIterator<String> iterator = items.listIterator();
// Forward iteration System.out.println("Forward iteration:"); while (iterator.hasNext()) { String item = iterator.next(); System.out.println("Next: " + item); }
// Backward iteration System.out.println("\nBackward iteration:"); while (iterator.hasPrevious()) { String item = iterator.previous(); System.out.println("Previous: " + item); }
// Adding elements during iteration ListIterator<String> addIterator = items.listIterator(); while (addIterator.hasNext()) { String item = addIterator.next(); if (item.equals("b")) { addIterator.add("b1"); // Add after current element } }
// Modifying elements during iteration ListIterator<String> modifyIterator = items.listIterator(); while (modifyIterator.hasNext()) { String item = modifyIterator.next(); if (item.equals("c")) { modifyIterator.set("c1"); // Replace current element } } }}Enhanced For-Loop
Section titled “Enhanced For-Loop”The enhanced for-loop is syntactic sugar that internally uses an Iterator.
public class EnhancedForLoopExample { public void demonstrateEnhancedForLoop() { List<String> fruits = Arrays.asList("apple", "banana", "cherry");
// Basic usage for (String fruit : fruits) { System.out.println(fruit); }
// With arrays String[] colors = {"red", "green", "blue"}; for (String color : colors) { System.out.println(color); }
// With sets Set<Integer> numbers = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5)); for (Integer number : numbers) { System.out.println(number); }
// With maps (iterating over entrySet) Map<String, Integer> scores = Map.of("Alice", 95, "Bob", 87, "Charlie", 92); for (Map.Entry<String, Integer> entry : scores.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); } }}Stream API Iteration
Section titled “Stream API Iteration”The Stream API provides a functional approach to collection processing.
public class StreamIterationExample { public void demonstrateStreamAPI() { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve");
// Basic iteration names.stream().forEach(System.out::println);
// Filtering and processing names.stream() .filter(name -> name.length() > 4) .map(String::toUpperCase) .forEach(System.out::println);
// Collecting results List<String> longNames = names.stream() .filter(name -> name.length() > 4) .collect(Collectors.toList());
// Parallel processing names.parallelStream() .forEach(System.out::println);
// Finding elements Optional<String> firstLongName = names.stream() .filter(name -> name.length() > 4) .findFirst();
// Counting elements long count = names.stream() .filter(name -> name.length() > 4) .count(); }}forEach Method
Section titled “forEach Method”The forEach method provides a simple way to iterate with lambda expressions.
public class ForEachExample { public void demonstrateForEach() { List<String> items = Arrays.asList("item1", "item2", "item3");
// Basic forEach items.forEach(item -> System.out.println(item));
// Method reference items.forEach(System.out::println);
// With index (using IntStream) IntStream.range(0, items.size()) .forEach(i -> System.out.println(i + ": " + items.get(i)));
// With maps Map<String, Integer> scores = Map.of("Alice", 95, "Bob", 87); scores.forEach((name, score) -> System.out.println(name + " scored " + score)); }}Traditional Index-Based Iteration
Section titled “Traditional Index-Based Iteration”For List implementations that support random access, index-based iteration can be efficient.
public class IndexBasedIterationExample { public void demonstrateIndexBasedIteration() { List<String> items = Arrays.asList("a", "b", "c", "d", "e");
// Forward iteration for (int i = 0; i < items.size(); i++) { String item = items.get(i); System.out.println("Index " + i + ": " + item); }
// Backward iteration for (int i = items.size() - 1; i >= 0; i--) { String item = items.get(i); System.out.println("Index " + i + ": " + item); }
// Skipping elements for (int i = 0; i < items.size(); i += 2) { String item = items.get(i); System.out.println("Even index " + i + ": " + item); } }}Iteration Performance Considerations
Section titled “Iteration Performance Considerations”Performance Comparison
Section titled “Performance Comparison”| Iteration Method | Performance | Memory | Safety | Use Case |
|---|---|---|---|---|
| Iterator | Good | Low | High | Safe removal, generic |
| Enhanced For-Loop | Good | Low | High | Simple iteration |
| ListIterator | Good | Low | High | Bidirectional, modification |
| Stream API | Variable | Medium | High | Functional processing |
| forEach | Good | Low | High | Lambda expressions |
| Index-based | Excellent* | Low | Medium | Random access lists |
* Only for ArrayList and other random-access implementations
Best Practices
Section titled “Best Practices”- Use Iterator for safe removal during iteration
- Use enhanced for-loop for simple iteration
- Use Stream API for complex processing and filtering
- Use index-based iteration only for ArrayList and similar
- Avoid modifying collections during enhanced for-loop iteration
Common Pitfalls
Section titled “Common Pitfalls”ConcurrentModificationException
Section titled “ConcurrentModificationException”// ❌ This will throw ConcurrentModificationExceptionList<String> items = new ArrayList<>(Arrays.asList("a", "b", "c"));for (String item : items) { if (item.equals("b")) { items.remove(item); // Exception! }}
// ✅ Use Iterator for safe removalIterator<String> iterator = items.iterator();while (iterator.hasNext()) { String item = iterator.next(); if (item.equals("b")) { iterator.remove(); // Safe! }}Infinite Loops
Section titled “Infinite Loops”// ❌ Potential infinite loop with IteratorIterator<String> iterator = items.iterator();while (iterator.hasNext()) { String item = iterator.next(); items.add("new item"); // Never reaches end!}
// ✅ Be careful with collection modifications during iterationAdvanced Iteration Patterns
Section titled “Advanced Iteration Patterns”Custom Iterators
Section titled “Custom Iterators”public class CustomIteratorExample { public static class RangeIterator implements Iterator<Integer> { private int current; private final int end;
public RangeIterator(int start, int end) { this.current = start; this.end = end; }
@Override public boolean hasNext() { return current < end; }
@Override public Integer next() { if (!hasNext()) { throw new NoSuchElementException(); } return current++; } }
public void demonstrateCustomIterator() { Iterator<Integer> rangeIterator = new RangeIterator(1, 6); while (rangeIterator.hasNext()) { System.out.println(rangeIterator.next()); } }}Spliterator for Parallel Processing
Section titled “Spliterator for Parallel Processing”public class SpliteratorExample { public void demonstrateSpliterator() { List<String> items = Arrays.asList("a", "b", "c", "d", "e", "f");
Spliterator<String> spliterator = items.spliterator();
// Try to split for parallel processing Spliterator<String> secondHalf = spliterator.trySplit();
// Process first half spliterator.forEachRemaining(item -> System.out.println("First half: " + item));
// Process second half secondHalf.forEachRemaining(item -> System.out.println("Second half: " + item)); }}Summary
Section titled “Summary”Java provides multiple iteration mechanisms, each suited for different scenarios:
- Iterator: Best for safe modification during iteration
- Enhanced For-Loop: Simplest syntax for basic iteration
- ListIterator: Bidirectional iteration with modification capabilities
- Stream API: Functional programming approach for complex processing
- forEach: Simple lambda-based iteration
- Index-based: Best performance for random-access lists
Choose the appropriate iteration method based on your specific requirements for performance, safety, and functionality.