Back to Blog
Java

Java Enhanced For Loop: Syntax, Behavior, and Limits

java enhanced for loop: Learn how the Java enhanced for loop works with arrays and Iterables, its limitations, and when to use classic for loops or streams instead.

Java loopsfor-eachIterableJava collectionsJava iteration
Diagram showing a Java enhanced for loop iterating over a collection with a highlighted loop variable.

The java enhanced for loop, also called the for-each loop, is a concise way to iterate over arrays and objects that implement Iterable. It was introduced in Java 5 and removes the need for explicit index management or iterator calls. The syntax is straightforward:

for (Type element : iterable) { // process element }

The Enhanced For Loop Syntax and Its Scope

The enhanced for loop works with two kinds of targets: arrays and objects that implement java.lang.Iterable. For arrays, the loop reads each element sequentially. For Iterable objects, it uses the iterator returned by iterator() and calls hasNext() and next() behind the scenes. The loop variable is read-only in the sense that reassigning it does not affect the underlying collection.

List<String> names = List.of("Ada", "Grace", "Linus"); for (String name : names) { System.out.println(name); }

This is equivalent to:

for (Iterator<String> it = names.iterator(); it.hasNext(); ) { String name = it.next(); System.out.println(name); }

The compiler generates the iterator-based version for Iterable targets. For arrays, it generates a simple indexed loop.

How the Enhanced For Loop Works with Arrays

When the target is an array, the enhanced for loop compiles to a traditional indexed loop. It reads each element in order, from index 0 to length-1. The loop variable receives a copy of the element, so modifying it has no effect on the array.

int[] numbers = {1, 2, 3}; for (int n : numbers) { n = n * 2; // does not change numbers } // numbers remains {1, 2, 3}

For reference types, the loop variable holds a reference to the same object, so mutating the object's state is possible, but reassigning the variable is not reflected in the array.

How the Enhanced For Loop Works with Iterables

For any object implementing Iterable, the enhanced for loop uses the iterator returned by the iterator() method. This means it works with all Collection types, custom iterables, and any class that provides an iterator. The loop automatically calls hasNext() before each iteration and next() to retrieve the element.

Set<Integer> ids = new HashSet<>(List.of(10, 20, 30)); for (Integer id : ids) { System.out.println(id); }

Because the loop relies on the iterator, the iteration order is determined by the collection's iterator implementation. For a HashSet, the order is unspecified; for a TreeSet, it is sorted; for a LinkedList, it is insertion order.

When the Enhanced For Loop Cannot Replace the Classic For Loop

The enhanced for loop hides the index and the iterator. That makes it unsuitable for scenarios where you need the index, such as modifying the current element in an array, or when you need to skip or remove elements during iteration without using an explicit iterator.

If you need the index, use a classic indexed loop:

for (int i = 0; i < array.length; i++) { array[i] = array[i] * 2; }

The enhanced for loop also cannot be used to iterate over multiple collections simultaneously or to iterate backwards. In those cases, you need explicit index or iterator control.

Modifying Collections During Iteration

A common pitfall is attempting to remove elements from a collection while using the enhanced for loop. The loop uses the collection's iterator, and most iterators are fail-fast. If the collection is structurally modified after the iterator is created, the iterator throws a ConcurrentModificationException on the next call to hasNext() or next().

List<String> items = new ArrayList<>(List.of("a", "b", "c")); for (String item : items) { if (item.equals("b")) { items.remove(item); // throws ConcurrentModificationException } }

To remove elements safely, use an explicit Iterator and call remove() on the iterator, or use removeIf in Java 8+:

items.removeIf(item -> item.equals("b"));

The enhanced for loop is also not safe for adding elements during iteration for the same reason.

Performance and Runtime Cost of the Enhanced For Loop

For arrays, the enhanced for loop compiles to the same bytecode as a classic indexed loop, so there is no performance penalty. For Iterable objects, the loop uses the iterator, which adds one method call per iteration for hasNext() and next(). In most applications, this overhead is negligible compared to the actual work inside the loop.

A more significant cost appears when the iterator is created. Some collections, like ArrayList, return a lightweight iterator. Others, like LinkedList, also have a lightweight iterator. However, if you iterate over a Stream or a custom Iterable that performs expensive work in next(), the cost is in that method, not in the loop itself.

If you are micro-optimizing, the enhanced for loop is generally as fast as an explicit iterator loop. The classic indexed loop can be faster for ArrayList because it avoids the iterator's hasNext() and next() calls, but the difference is rarely measurable in real applications. Prefer the enhanced for loop for readability unless profiling shows a bottleneck.

Choosing Between Enhanced For Loop and Streams

Java 8 introduced streams, which provide a different way to process collections. Streams allow functional-style operations like filter, map, and collect. The enhanced for loop is imperative and works well when you need to perform side effects on each element or when the logic is simple.

// Enhanced for loop for (String name : names) { if (name.startsWith("A")) { System.out.println(name.toUpperCase()); } } // Stream equivalent names.stream() .filter(name -> name.startsWith("A")) .map(String::toUpperCase) .forEach(System.out::println);

Use the enhanced for loop when:

  • You need to break or return early from the loop.
  • You need to modify local variables outside the loop.
  • You are iterating over an array and need the index (though a classic loop is clearer).
  • The iteration logic is simple and side-effect oriented.

Use streams when you need to chain transformations, work with parallel processing, or prefer a declarative style. Streams cannot easily break early, and they have overhead for simple loops. The enhanced for loop remains the most readable and efficient choice for many everyday iteration tasks.

java enhanced for loop: Practical Usage and Code Examples | RYUSLOG DEV