What’s the ways to iterate over a list in Java ?

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

MethodModification Allowed?DirectionUse Case
Basic forYes (by index)ForwardIndex access or modification
Enhanced forNoForwardSimple read-only iteration
IteratorRemove onlyForwardSafe element removal
ListIteratorFull modificationBidirectionalComplex edits or backward traversal
forEach() + LambdaNoForwardRead-only with concise syntax
Streams APINoForwardChained operations (filter/map/etc.)

Critical Notes

  • Concurrent Modification:
  • Use Iterator/ListIterator for safe removal during iteration.
  • Modifying a list with add()/remove() while using a for-loop or forEach() throws ConcurrentModificationException.
  • Performance:
  • ArrayList: All methods efficient.
  • LinkedList: Avoid index-based loops (slow get(i)), prefer Iterator or for-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!

Leave a Reply

Your email address will not be published. Required fields are marked *