Back to Blog
Java

Java Foreach Loop: Syntax, Behavior, and Limitations

java foreach loop: Understand the Java foreach loop: its syntax, how it compiles to iterators, common pitfalls, and when to choose it over indexed loops.

enhanced for loopiterationcollectionsarraysperformance
Diagram showing a Java foreach loop iterating over a collection with an iterator symbol

The java foreach loop, also known as the enhanced for loop, provides a concise syntax for iterating over arrays and collections without explicitly managing an index or iterator. It was introduced in Java 5 and has become a standard way to traverse elements in everyday code.

The Syntax of the Enhanced For Loop

The basic syntax is:

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

Here, iterable can be an array or any object that implements java.lang.Iterable, such as List, Set, or Queue. The loop variable element takes each value from the collection in order.

Example:

List<String> names = Arrays.asList("Alice", "Bob", "Carol"); for (String name : names) { System.out.println(name); }

This prints each name. The loop variable is read-only; assigning a new value to name does not modify the underlying collection.

How the Foreach Loop Works Under the Hood

The enhanced for loop is syntactic sugar. For arrays, it compiles to an indexed loop using the array's length. For collections, it compiles to a loop using an Iterator obtained from the iterator() method.

For example, this code:

for (String s : list) { System.out.println(s); }

is roughly equivalent to:

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

This means the foreach loop inherits the behavior of the underlying iterator, including fail-fast behavior in java.util collections.

Iterating Over Different Collection Types

The foreach loop works uniformly across arrays and all Iterable types.

Arrays

int[] numbers = {1, 2, 3}; for (int n : numbers) { System.out.println(n); }

Lists and Sets

Set<String> uniqueNames = new HashSet<>(Arrays.asList("Alice", "Bob")); for (String name : uniqueNames) { System.out.println(name); }

Maps

Maps are not Iterable directly. To iterate over entries, you use entrySet():

Map<String, Integer> ages = new HashMap<>(); ages.put("Alice", 30); for (Map.Entry<String, Integer> entry : ages.entrySet()) { System.out.println(entry.getKey() + " is " + entry.getValue()); }

Common Pitfalls and Limitations

The foreach loop is convenient but has constraints.

No Index Information

You cannot access the current index directly. If you need the index, you must maintain a separate counter or fall back to a traditional for loop.

Cannot Modify the Collection During Iteration

Attempting to add or remove elements inside a foreach loop over a java.util collection throws ConcurrentModificationException because the iterator detects structural modification. For example:

List<String> words = new ArrayList<>(Arrays.asList("a", "b", "c")); for (String w : words) { if (w.equals("b")) { words.remove(w); // throws ConcurrentModificationException } }

To remove elements safely, use an explicit Iterator and its remove() method, or use removeIf on Java 8+.

Loop Variable Is a Copy

For primitive arrays, the loop variable is a copy of the element. For object arrays, it is a reference copy. Assigning to the loop variable does not affect the array or collection.

Performance Considerations

The foreach loop is often as fast as an indexed loop for arrays, but for collections it incurs the overhead of an iterator. In most applications, the difference is negligible. However, if you are iterating over a large ArrayList and need the index, an indexed loop may be slightly faster because it avoids iterator method calls. For LinkedList, an indexed loop is significantly slower because get(index) traverses the list each time; the foreach loop is the correct choice there.

The foreach loop also prevents common off-by-one errors and makes the code more readable, which often outweighs micro-optimizations.

When to Use the Foreach Loop and When to Avoid It

Use the foreach loop when you need to process every element in an array or Iterable and do not need the index or the ability to modify the collection structure. It is the clearest expression of intent.

Avoid it when:

  • You need the index to perform calculations.
  • You need to modify the collection during iteration (use an explicit iterator or removeIf).
  • You are iterating over a LinkedList and accidentally use get(index) in a traditional loop; the foreach loop is better.
  • You need to iterate over multiple collections in parallel; a traditional indexed loop may be clearer.

Foreach with Custom Iterable Types

You can use the foreach loop with any class that implements Iterable<T>. This requires implementing iterator() to return an Iterator<T>. This is useful for custom data structures or when you want to provide a clean iteration interface.

Example:

public class Range implements Iterable<Integer> { private final int start; private final int end; public Range(int start, int end) { this.start = start; this.end = end; } @Override public Iterator<Integer> iterator() { return new Iterator<Integer>() { private int current = start; @Override public boolean hasNext() { return current < end; } @Override public Integer next() { return current++; } }; } }

Then:

for (int n : new Range(1, 5)) { System.out.println(n); // prints 1 2 3 4 }

Compatibility and Version Notes

The enhanced for loop has been part of Java since version 5.0. It works with all later versions without changes. The behavior is identical across Java 8, 11, 17, and 21. If you are using a modern JDK, you can also consider Stream.forEach, but that is a different mechanism with different semantics (e.g., no guaranteed order for parallel streams, and it does not allow early termination with break).

java foreach loop: Practical Usage and Code Examples | RYUSLOG DEV