5.3 The Enhanced For-Each Loop

Key Takeaways

  • The enhanced for loop (for-each) provides a concise, index-free syntax for forward-only sequential traversal of arrays and java.lang.Iterable collections.
  • When traversing primitive arrays, the loop control variable receives a copy of each element's value, making the traversal strictly read-only for array contents.
  • When traversing object collections, the loop variable holds a copy of the reference pointer; mutating the referenced object modifies heap state, but reassigning the variable does not affect array or collection slots.
  • Structurally modifying a collection (calling list.add() or list.remove()) during an enhanced for-loop traversal is a defect that normally throws ConcurrentModificationException on the next iteration step; removing the second-to-last element is the one data-dependent case that escapes detection because hasNext() ends the loop first.
  • Enhanced for loops cannot access current index positions, cannot traverse backwards, cannot skip elements, and cannot traverse multiple data structures in parallel.
Last updated: September 2026

5.3 The Enhanced For-Each Loop

[!NOTE] Exam Focus: Introduced in Java 5, the enhanced for loop (commonly termed the "for-each" loop) carries its own objective inside Oracle's "Using Looping Statements" topic area: "use a for loop including an enhanced for loop". The 1Z0-811 examination specifically tests candidates on its syntax rules, its underlying read-only mechanics regarding primitive elements, the runtime ConcurrentModificationException caused by altering collections during iteration, and the scenarios where developers must revert to standard indexed loops.

Traditional indexed for loops require declaring a counter variable, establishing a boundary expression (such as i < array.length), and manually updating the counter (i++). This repetitive boilerplate code introduces frequent opportunities for off-by-one errors and indexing bugs. To eliminate these hazards when simply inspecting or aggregating sequential data, Java provides the enhanced for loop.


Syntax and Semantic Structure

The enhanced for loop eliminates explicit counter variables and index subscripts entirely, replacing them with a variable declaration and a target expression separated by a colon (:):

for (elementType variableName : targetExpression) {
    // Loop body: executes once for each element in targetExpression
}

Syntactic Components

  1. Element Declaration (elementType variableName): Declares a block-scoped local variable. Its data type must be assignable from (compatible with) the elements of the array or collection being traversed.
  2. Target Expression (targetExpression): Must evaluate to either an array or an instance of a class that implements the java.lang.Iterable interface (such as ArrayList, HashSet, or LinkedList). Passing a primitive type, null, or an arbitrary non-iterable class triggers an immediate compile-time error (foreach not applicable to type).
  3. Colon (:): Read aloud as "in". For example, for (String name : names) is read as "for each String name in names".
String[] colors = {"Red", "Green", "Blue"};
for (String color : colors) {
    System.out.println(color);
}

Traversal Across Arrays and Collections

1. One-Dimensional Arrays

In a single-dimensional array, the enhanced for loop extracts elements sequentially from index 0 up to array.length - 1:

int[] grades = {85, 92, 78, 96};
int sum = 0;
for (int grade : grades) {
    sum += grade;
}
System.out.println("Average: " + (sum / (double) grades.length)); // Prints: Average: 87.75

2. Multi-Dimensional and Ragged (Jagged) Arrays

In Java, a two-dimensional array is an "array of arrays". Consequently, traversing a 2D array with enhanced for loops requires nested loops:

  • The outer loop retrieves each one-dimensional array row (int[] row).
  • The inner loop extracts each individual primitive integer (int val) from that row.
int[][] matrix = {
    {1, 2},
    {3, 4, 5} // Ragged row with 3 elements
};

for (int[] row : matrix) { // Outer loop extracts 1D array row
    for (int val : row) {   // Inner loop extracts primitive values
        System.out.print(val + " ");
    }
}
// Output: 1 2 3 4 5

Notice that ragged arrays with uneven row lengths are processed seamlessly because the inner loop automatically binds to the specific length of each row.

3. ArrayList Collections and Autoboxing

When traversing an ArrayList, the declared variable type must be compatible with the list's generic element type. Java automatically handles autoboxing and unboxing:

ArrayList<Integer> scores = new ArrayList<Integer>();
scores.add(90); // Autoboxed from int to Integer
scores.add(85);

// Unboxes Integer object to primitive int automatically
for (int score : scores) {
    System.out.println("Score: " + score);
}

Compiler Desugaring Mechanics

The enhanced for loop is "syntactic sugar"—a high-level language convenience that the Java compiler (javac) translates into standard low-level bytecode patterns:

1. Desugaring for Arrays

When compiling an enhanced for loop over an array, javac generates an internal temporary index variable and a standard indexed for loop:

// What you write:
for (int num : numbers) {
    System.out.println(num);
}

// What javac generates internally:
int[] tempArray = numbers;
for (int tempIdx = 0; tempIdx < tempArray.length; tempIdx++) {
    int num = tempArray[tempIdx];
    System.out.println(num);
}

2. Desugaring for Iterable Collections

When compiling an enhanced for loop over an ArrayList or other Iterable, javac generates an explicit java.util.Iterator loop:

// What you write:
for (String item : itemList) {
    System.out.println(item);
}

// What javac generates internally:
for (Iterator<String> it = itemList.iterator(); it.hasNext(); ) {
    String item = it.next();
    System.out.println(item);
}

The Read-Only Traversal Nature: Primitive Arrays

One of the most heavily tested traps on the 1Z0-811 examination concerns attempting to modify array data within an enhanced for loop.

The Local Copy Trap

When an enhanced for loop traverses an array of primitives, the loop control variable is an independent local stack variable that receives a copy of the value stored in the array at that index. Reassigning the loop variable has zero effect on the underlying array:

int[] data = {10, 20, 30};
for (int x : data) {
    x = x * 2; // Modifies only the local stack variable x!
}

System.out.println(data[0] + ", " + data[1] + ", " + data[2]);
// Output: 10, 20, 30 (UNMODIFIED!)

To modify array elements in place, a traditional indexed for loop must be used (data[i] = data[i] * 2;).


Object Traversal: Reference Copying vs. State Mutation

When traversing an array or collection of objects, understanding the difference between modifying an object's internal state versus reassigning the reference variable is crucial:

class Account {
    int balance;
    Account(int b) { balance = b; }
}

Account[] accounts = { new Account(100), new Account(200) };

for (Account acc : accounts) {
    acc.balance += 50;      // 1. MUTATES HEAP OBJECT: Changes underlying object state!
    acc = new Account(999); // 2. REASSIGNS LOCAL REFERENCE: Has zero effect on array!
}

System.out.println(accounts[0].balance); // Prints 150, NOT 999 or 100!
System.out.println(accounts[1].balance); // Prints 250, NOT 999 or 200!
  1. Mutating Heap State (acc.balance += 50): The variable acc holds a copy of the reference pointer pointing to the heap object. Invoking mutators or updating fields directly modifies the actual object in memory. This mutation is reflected in the array.
  2. Reassigning the Reference (acc = new Account(999)): Reassigning acc merely points the local stack variable to a newly instantiated object on the heap. The original reference stored in the accounts array remains completely unchanged.

Critical Limitations of the Enhanced for Loop

Despite its clarity and conciseness, the enhanced for loop is unsuitable in several common programming scenarios:

1. Structural Modification of Collections (ConcurrentModificationException)

You cannot add or remove elements from an ArrayList or collection while traversing it with an enhanced for loop. Because the loop compiles to an internal Iterator, modifying the list directly causes the iterator's modification count (modCount) to fall out of sync with its expected count, triggering a runtime exception:

ArrayList<String> names = new ArrayList<String>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");

for (String name : names) {
    if (name.equals("Alice")) {
        names.remove(name); // RUNTIME ERROR: java.util.ConcurrentModificationException
    }
}

To safely remove elements during traversal, developers must use an explicit Iterator and invoke its remove() method (iterator.remove()).

[!CAUTION] The Second-to-Last Element Loophole (Know This Precisely): The ConcurrentModificationException is not raised by remove() itself — it is raised by the next call to it.next(), which compares the list's modCount against the iterator's expected count. The iterator's hasNext() simply tests cursor != size. So if you remove the second-to-last element, size drops to exactly equal cursor, hasNext() returns false, the loop exits normally, and no exception is ever thrown:

ArrayList<String> ids = new ArrayList<String>();
ids.add("A101");
ids.add("B202");
ids.add("C303");

for (String id : ids) {
    if (id.equals("B202")) { // B202 is the second-to-last element
        ids.remove(id);      // No exception! Loop simply ends early.
    }
}
System.out.println(ids); // Prints: [A101, C303]

This is exactly why structural modification during a for-each loop is a defect even when it appears to "work": the failure is data-dependent. Removing "A101" from the same list throws immediately, while removing "B202" silently succeeds.

2. Lack of Index Access

The enhanced for loop does not expose the current index position. If your algorithm requires the index—such as printing line numbers, updating specific array slots, or searching for an index—maintaining an external counter defeats the architectural purpose of the construct.

3. Forward-Only, Single-Step Traversal

Enhanced for loops move strictly forward, visiting every element from first to last in single steps. They cannot:

  • Traverse in reverse order (e.g., from length - 1 down to 0).
  • Skip elements (e.g., visiting only even indices with i += 2).

4. Parallel Data Structure Traversal

You cannot iterate through two arrays or collections simultaneously in lockstep (e.g., matching students[i] with grades[i]).


Architectural Comparison: Standard vs. Enhanced for Loops

Capability / RequirementStandard for LoopEnhanced for Loop
Access Current IndexYes (i directly accessible)No (requires external counter variable)
Modify Array PrimitivesYes (array[i] = newVal;)No (reassigning loop variable does nothing)
Reverse / Custom StrideYes (i--, i += 2)No (strictly forward by 1 element)
Remove During TraversalYes (with careful index tracking)No (throws ConcurrentModificationException)
Safety from Bounds BugsError-prone (< vs <=, off-by-one)Immune to off-by-one indexing errors
Primary Use CasesElement mutation, indexed access, steppingRead-only iteration, summing, searching
Loading diagram...
Enhanced for Loop: Value Copying vs. Reference Mutation
Test Your Knowledge

What is the output of the following Java program?

class Item {
    int qty;
    Item(int q) { this.qty = q; }
}

Item[] items = { new Item(5), new Item(8) };
for (Item it : items) {
    it.qty += 10;
    it = new Item(99);
}
System.out.println(items[0].qty + "," + items[1].qty);

A
B
C
D
Test Your Knowledge

Consider the following code snippet that manipulates a list of customer identifiers:

ArrayList<String> ids = new ArrayList<String>();
ids.add("A101");
ids.add("B202");
ids.add("C303");

for (String id : ids) {
    if (id.equals("A101")) {
        ids.remove(id);
    }
}
What is the outcome when this code is executed?

A
B
C
D
Test Your Knowledge

What is the output of the following Java program?

int[][] matrix = {
    {1, 2},
    {3},
    {4, 5, 6}
};
int count = 0;
int sum = 0;
for (int[] row : matrix) {
    for (int val : row) {
        count++;
        sum += val;
    }
}
System.out.println("count=" + count + ", sum=" + sum);

A
B
C
D