In Java, there are several ways to iterate over a List
, each with specific use cases. Below is a detailed explanation with examples:
1. Basic for
Loop (Index-Based)
Best for accessing elements by index or modifying during iteration.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>(List.of("Apple", "Banana", "Cherry"));
for (int i = 0; i < fruits.size(); i++) {
String fruit = fruits.get(i);
System.out.println(fruit);
// Modify elements safely:
if (fruit.equals("Banana")) {
fruits.set(i, "Mango"); // Replace element
}
}
// Output: Apple, Mango, Cherry
}
}
2. Enhanced for
Loop (For-Each)
Simplest syntax for read-only traversal. Cannot modify the list during iteration.
for (String fruit : fruits) {
System.out.println(fruit);
// fruits.remove("Apple"); // Throws ConcurrentModificationException!
}
3. Iterator
Safe for element removal during iteration. Use for forward-only traversal.
import java.util.Iterator;
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
String fruit = iterator.next();
if (fruit.equals("Cherry")) {
iterator.remove(); // Safely remove current element
}
}
// Fruits now: [Apple, Mango]
4. ListIterator
Bidirectional traversal + add/remove/set operations. Use for complex list modifications.
ListIterator<String> listIterator = fruits.listIterator(fruits.size()); // Start at end
// Backward iteration
while (listIterator.hasPrevious()) {
String fruit = listIterator.previous();
if (fruit.startsWith("A")) {
listIterator.set("Apricot"); // Modify element
}
}
// Fruits now: [Apricot, Mango]
5. forEach()
+ Lambda (Java 8+)
Concise syntax for read-only iteration. Avoid modification.
fruits.forEach(fruit -> System.out.println(fruit));
// Method reference alternative:
fruits.forEach(System.out::println);
6. Streams API (Java 8+)
For parallel processing, filtering, mapping, etc.
fruits.stream()
.filter(f -> f.length() > 5)
.map(String::toUpperCase)
.forEach(System.out::println); // Output: "APRICOT"
Key Differences & Recommendations
Method | Modification Allowed? | Direction | Use Case |
---|---|---|---|
Basic for | Yes (by index) | Forward | Index access or modification |
Enhanced for | No | Forward | Simple read-only iteration |
Iterator | Remove only | Forward | Safe element removal |
ListIterator | Full modification | Bidirectional | Complex edits or backward traversal |
forEach() + Lambda | No | Forward | Read-only with concise syntax |
Streams API | No | Forward | Chained operations (filter/map/etc.) |
Critical Notes
- Concurrent Modification:
- Use
Iterator
/ListIterator
for safe removal during iteration. - Modifying a list with
add()
/remove()
while using afor
-loop orforEach()
throwsConcurrentModificationException
. - Performance:
ArrayList
: All methods efficient.LinkedList
: Avoid index-based loops (slowget(i)
), preferIterator
orfor
-each.- Java 8+: Use streams for complex data processing pipelines.
Example: Safe Removal with Iterator
List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3, 4));
Iterator<Integer> numIterator = numbers.iterator();
while (numIterator.hasNext()) {
int num = numIterator.next();
if (num % 2 == 0) {
numIterator.remove(); // Remove even numbers
}
}
// numbers becomes [1, 3]
Choose the iteration method based on whether you need modification, bidirectional access, or simplicity!