Enhanced for Loop
The enhanced for-loop (for-each) offers a clean, error-resistant way to walk through arrays and any Iterable, at the cost of index access and safe in-loop modification.
The enhanced for-loop, introduced in Java 5, iterates over every element of an array or Iterable without manual index or iterator bookkeeping. It reads cleanly and eliminates a whole class of off-by-one bugs, but it trades away index access and cannot safely modify the underlying collection's structure mid-loop.
What Is the Enhanced for-loop
Syntax: for (ElementType variable : source) { ... }, where source is either an array or anything implementing Iterable<ElementType>. On each iteration, variable is bound to the next element in sequence.
int[] nums = {10, 20, 30};
for (int n : nums) {
System.out.println(n);
}
List<String> names = List.of("Ann", "Bob", "Carl");
for (String name : names) {
System.out.println(name);
}Working with Arrays
For arrays, the compiler generates code equivalent to a traditional indexed loop internally (arrays don't implement Iterable — they get special compiler support), so there's no iterator overhead for arrays specifically.
int[][] grid = {{1, 2}, {3, 4}};
for (int[] row : grid) {
for (int val : row) {
System.out.print(val + " ");
}
}
// 1 2 3 4Working with Iterable
For any Iterable (all standard collections except Map, which needs .keySet()/.values()/.entrySet()), the loop desugars to an explicit Iterator under the hood, as covered in the Iterable & Iterator topic.
Map<String, Integer> ages = Map.of("Ann", 30, "Bob", 25);
for (Map.Entry<String, Integer> entry : ages.entrySet()) {
System.out.println(entry.getKey() + " is " + entry.getValue());
}
// Map itself is NOT Iterable, but entrySet()/keySet()/values() areIterator Relationship
For an Iterable source, for (T x : iterable) is exactly equivalent to obtaining iterable.iterator() once and repeatedly calling hasNext()/next(). This means all the underlying Iterator behavior — including fail-fast ConcurrentModificationException — applies to enhanced for-loops too.
// These two loops behave identically:
for (String s : list) {
System.out.println(s);
}
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}No Index Access
The enhanced for-loop doesn't expose the current index. If you need the index (e.g. to print 'item #3' or access a parallel array), use a traditional indexed for loop, or track a separate counter manually.
List<String> names = List.of("Ann", "Bob", "Carl");
int index = 0;
for (String name : names) {
System.out.println(index + ": " + name);
index++;
}
// Or simply use: for (int i = 0; i < names.size(); i++) { ... }Modification Caveats
Reassigning the loop variable inside the body does NOT modify the underlying array or collection — for arrays, the variable is a copy of the element's value (or, for object elements, a copy of the reference); for Iterable sources, the variable is whatever next() returned. Assigning to it only rebinds the local variable, not the source.
Structurally modifying the underlying collection (add/remove) during a for-each over it typically throws ConcurrentModificationException, because the loop is using a plain Iterator under the hood with no way to call remove() itself.
int[] arr = {1, 2, 3};
for (int n : arr) {
n = n * 10; // only changes the local copy
}
System.out.println(Arrays.toString(arr)); // [1, 2, 3] - unchangedMutating Object Fields Is Different
While reassigning the loop variable has no effect on the source, calling a mutating method ON the object it refers to does affect the real object, since the loop variable holds a real reference to it.
List<StringBuilder> items = List.of(new StringBuilder("a"), new StringBuilder("b"));
for (StringBuilder sb : items) {
sb.append("!"); // mutates the actual object - this DOES take effect
}
System.out.println(items); // [a!, b!]Rules and Behavior
The loop's source expression is evaluated exactly once at the start (for Iterable, iterator() is called once). It supports break and continue exactly like a traditional for loop. It cannot loop backwards or skip elements by index — those require a traditional for or explicit Iterator/ListIterator.
Practical Usage
Prefer the enhanced for-loop whenever you need to visit every element and don't need the index or in-loop structural modification — it's shorter, avoids off-by-one errors, and works uniformly across arrays and all Iterable types.
double total = 0;
for (double price : List.of(9.99, 4.50, 12.00)) {
total += price;
}
System.out.println(total); // 26.49Edge Cases
Iterating a null array or null Iterable reference throws NullPointerException immediately when the loop tries to evaluate the source. Iterating an empty array or empty collection simply runs the loop body zero times without error.
int[] arr = null;
for (int n : arr) { } // throws NullPointerException immediately
for (int n : new int[0]) {
System.out.println("never runs");
} // no output, no errorComplete Example
import java.util.*;
public class ForEachDemo {
public static void main(String[] args) {
Map<String, Integer> inventory = new LinkedHashMap<>();
inventory.put("apples", 12);
inventory.put("pears", 5);
inventory.put("bananas", 0);
for (Map.Entry<String, Integer> entry : inventory.entrySet()) {
String status = entry.getValue() == 0 ? "OUT OF STOCK" : entry.getValue() + " in stock";
System.out.println(entry.getKey() + ": " + status);
}
}
}Mental Model
Think of the enhanced for-loop as a read-only tour guide: it walks you past every item in order, letting you look at (and interact with) each one, but it doesn't hand you a map coordinate (index) and it doesn't let you rearrange the exhibit while the tour is in progress.
Quick Reference
for (Type var : arrayOrIterable) {
// var is a fresh binding each iteration
// reassigning var does NOT affect the source
// mutating an object var refers to DOES affect the source
// structural modification of a live collection -> ConcurrentModificationException
// no index available - use traditional for if you need one
}Key Takeaways
The enhanced for-loop works over arrays and anything implementing Iterable, but not directly over Map.
For Iterable sources, it desugars to explicit hasNext()/next() calls, so fail-fast ConcurrentModificationException applies the same way.
Reassigning the loop variable never affects the source; only mutating an object the variable references does.
There is no index in a for-each — use a traditional for loop when you need one.
Structurally modifying the source collection during a for-each (outside an explicit iterator's remove()) throws ConcurrentModificationException.
for (int n: arr) { n = n + 1; // no effect, just discarded } // arr unchanged - surprising to many beginners for (int i = 0; i < arr.length; i++) { arr[i] = arr[i] + 1; // actually mutates the array }
The for-each loop variable is a copy; reassigning it never writes back into the array or collection. Use an indexed loop to mutate array elements in place.
for (String s : list) { if (s.isEmpty()) list.remove(s); // throws ConcurrentModificationException }
Structurally modifying the collection during a for-each throws ConcurrentModificationException; removeIf (or an explicit Iterator's remove()) is the safe alternative.
for (String s: map) {... } // does not compile: Map is not Iterable for (String s: map.keySet()) {... } // or: for (Map.Entry<String, Integer> e: map.entrySet()) {... }
Map does not implement Iterable directly; iterate over one of its collection views (keySet, values, or entrySet).
Why can't you use a for-each loop directly over a Map?
Map does not implement the Iterable interface (it's a separate root of the Collections Framework), so you must iterate over one of its views instead: keySet(), values(), or entrySet().
Does reassigning the loop variable inside a for-each affect the source array or collection?
No — the loop variable is a fresh local binding each iteration (a copy of the element's value or reference); reassigning it only changes that local copy, never the underlying array slot or collection element.
Why does calling a mutator method on the for-each loop variable change the source, while reassigning the variable does not?
For object elements, the loop variable holds a real reference to the same object stored in the collection; calling a method on it (like append or set) mutates that shared object's state. Reassigning the variable itself, however, just points the local variable elsewhere without touching the object or the collection slot.
What happens if you try to add an element to a List while iterating it with a for-each loop?
It typically throws ConcurrentModificationException, because the for-each is using a plain Iterator under the hood whose fail-fast check detects the structural modification made outside the iterator's own remove() path.
How would you access the current index while using a for-each loop over a List?
You generally can't directly — you'd track a separate counter variable manually, or switch to a traditional indexed for loop (or use List.listIterator() for nextIndex()).
What happens when you use a for-each loop on a null array reference?
It throws NullPointerException as soon as the loop tries to evaluate the source expression, before any iteration begins.
Why do arrays support the for-each loop even though they don't implement Iterable?
The Java compiler gives arrays special built-in support for the enhanced for-loop syntax, generating index-based iteration code directly, rather than requiring arrays to implement the Iterable interface.
Write a program that computes the sum and average of an int array using a for-each loop.
public class SumAverage { public static void main(String[] args) { int[] scores = {80, 90, 70, 100, 60}; int sum = 0; for (int s : scores) { sum += s; } double average = (double) sum / scores.length; System.out.println("Sum: " + sum); System.out.println("Average: " + average); } }
The for-each loop accumulates sum across all elements: Sum: 400, Average: 80.0.
What does this print, and why?
[1, 2, 3]. n is a local copy of each element (auto-unboxed int); multiplying it does not write back to the immutable list, which also could not be modified even if it tried.
Write a program that uses a for-each loop over a Map<String, Integer> to print each entry, then uses removeIf to remove entries with a value less than 10 (not a for-each modification).
import java.util.*; public class MapForEach { public static void main(String[] args) { Map<String, Integer> scores = new LinkedHashMap<>(); scores.put("Ann", 15); scores.put("Bob", 5); scores.put("Carl", 20); for (Map.Entry<String, Integer> e : scores.entrySet()) { System.out.println(e.getKey() + " = " + e.getValue()); } scores.entrySet().removeIf(e -> e.getValue() < 10); System.out.println(scores); // {Ann=15, Carl=20} } }
The for-each loop prints all three entries in insertion order (LinkedHashMap). removeIf on the entrySet() view safely removes Bob (value 5 < 10) without a ConcurrentModificationException, leaving {Ann=15, Carl=20}.
List<Integer> nums = List.of(1, 2, 3);
for (int n : nums) {
n *= 100;
}
System.out.println(nums);