By WebNest Studio Engineering Team
Java - Core Tutorial
Java For-each Loop
The for-each loop (also called the "enhanced for loop"), introduced in Java 5, provides a simpler syntax for iterating over every element of an array or any object implementing Iterable, such as the collections in java.util. It removes the need to manage an index variable manually, which eliminates an entire category of off-by-one and ArrayIndexOutOfBoundsException bugs.
The syntax reads almost like plain English: for (Type element : collection) means "for each element of this type in this collection." Internally, for an array the compiler generates an equivalent indexed loop, and for an Iterable it generates calls to hasNext() and next() on an iterator — but you never have to write that machinery yourself.
Why it matters
The for-each loop removes the index, and with it a whole category of off-by-one mistakes, so it is the default way to read every element of an array or collection. Knowing its limits matters just as much: it cannot change which element an array holds, and removing from a collection inside one throws an exception that surprises most developers the first time.
Syntax and How It Works
On each iteration, the loop variable is assigned a copy of the next element in the array or collection, in order, and the body executes with that value available. The loop automatically stops after the last element, so there is no condition or index update to get wrong.
Watch: How the Java For-each Loop Works Internally
A quick video on what the compiler turns a for-each loop into for arrays and collections.
How It Works Internally: What the Compiler Generates
There is no special "for-each" instruction in the JVM. The compiler rewrites every enhanced for loop into an ordinary loop before producing bytecode, and it picks one of two shapes depending on what you loop over:
- Arrays become an indexed loop.
for (int n : nums) { ... }is compiled as if you wroteint[] a = nums; for (int i = 0; i < a.length; i++) { int n = a[i]; ... }. The array reference is captured once before the loop starts, so pointingnumsat a different array inside the body does not change what is being iterated. - Anything Iterable (List, Set, Queue, your own classes) becomes an iterator loop.
for (String s : list) { ... }is compiled asfor (Iterator<String> it = list.iterator(); it.hasNext(); ) { String s = it.next(); ... }. - The loop variable is a fresh local variable assigned from
a[i]orit.next()on every pass. That is why reassigning it never changes the array or collection — for objects it is a copy of the reference, so calling a method that changes the object itself (likesb.append("!")) does affect the original. - Because the generated code calls
list.iterator()(for a collection) or readsa.length(for an array) before the first pass, looping over anullcollection or array throws a NullPointerException before the body ever runs. - Any class that implements
Iterable<T>— that is, has aniterator()method — can be used in a for-each loop. Maps are not Iterable themselves, which is why you loop overmap.entrySet(),keySet()orvalues()instead.
Why Removing Inside for-each Throws ConcurrentModificationException
Collections like ArrayList keep an internal modification counter (modCount) that increases every time the list changes size. When the hidden iterator is created, it remembers that count. Every call to next() compares the two, and if the list was changed behind the iterator's back — for example by list.remove(x) inside the loop — it throws ConcurrentModificationException. This is a "fail-fast" safety check, not a threading problem. The fix is to remove through the iterator itself with an explicit Iterator and it.remove(), which updates both counters together, or to use list.removeIf(...), which does the same thing in one line.
Limitations of the For-each Loop
The convenience comes with real trade-offs that make for-each unsuitable for some tasks.
- The loop variable holds a copy of each element for primitives, so reassigning it inside the loop body does not modify the original array.
- There is no automatic access to the current index, which is a problem if you need to know an element's position or modify the array in place by index.
- You cannot easily iterate backward, skip elements, or iterate two collections in lockstep using a single for-each loop.
- You cannot safely add or remove elements from most collections while iterating over them with for-each — doing so throws a ConcurrentModificationException.
Examples
Iterating an int array and a String array with for-each
public class ForEachDemo {
public static void main(String[] args) {
int[] numbers = {2, 4, 6, 8, 10};
int sum = 0;
for (int num : numbers) {
sum += num;
}
System.out.println("Sum: " + sum);
String[] fruits = {"Apple", "Banana", "Cherry"};
for (String fruit : fruits) {
System.out.println(fruit);
}
}
}
Sum: 30
Apple
Banana
Cherry
What the compiler turns a for-each loop into, written out by hand for an array and a List
import java.util.Iterator;
import java.util.List;
public class ForEachInternalsDemo {
public static void main(String[] args) {
int[] nums = {10, 20, 30};
// What you write
for (int n : nums) {
System.out.print(n + " ");
}
System.out.println("<- for-each over array");
// What the compiler generates for an array
int[] a = nums;
for (int i = 0; i < a.length; i++) {
int n = a[i];
System.out.print(n + " ");
}
System.out.println("<- indexed loop");
List<String> langs = List.of("Java", "Python", "React");
// What you write
for (String s : langs) {
System.out.print(s + " ");
}
System.out.println("<- for-each over List");
// What the compiler generates for an Iterable
for (Iterator<String> it = langs.iterator(); it.hasNext(); ) {
String s = it.next();
System.out.print(s + " ");
}
System.out.println("<- iterator loop");
}
}
10 20 30 <- for-each over array
10 20 30 <- indexed loop
Java Python React <- for-each over List
Java Python React <- iterator loop
Your own class works in for-each as soon as it implements Iterable
import java.util.Iterator;
public class CountdownDemo {
static class Countdown implements Iterable<Integer> {
private final int start;
Countdown(int start) {
this.start = start;
}
@Override
public Iterator<Integer> iterator() {
return new Iterator<>() {
private int current = start;
@Override
public boolean hasNext() {
return current > 0;
}
@Override
public Integer next() {
return current--;
}
};
}
}
public static void main(String[] args) {
for (int n : new Countdown(5)) {
System.out.print(n + " ");
}
System.out.println("Liftoff!");
}
}
5 4 3 2 1 Liftoff!
Removing inside for-each fails fast; Iterator.remove() and removeIf() are the safe ways
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
public class SafeRemoveDemo {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));
try {
for (int n : nums) {
if (n % 2 == 0) {
nums.remove(Integer.valueOf(n));
}
}
} catch (ConcurrentModificationException e) {
System.out.println("for-each + list.remove(): ConcurrentModificationException");
}
List<Integer> a = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));
for (Iterator<Integer> it = a.iterator(); it.hasNext(); ) {
if (it.next() % 2 == 0) {
it.remove();
}
}
System.out.println("Iterator.remove(): " + a);
List<Integer> b = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));
b.removeIf(n -> n % 2 == 0);
System.out.println("removeIf(): " + b);
}
}
for-each + list.remove(): ConcurrentModificationException
Iterator.remove(): [1, 3, 5]
removeIf(): [1, 3, 5]
Common Mistakes
- Trying to modify an array element by assigning to the for-each loop variable, not realizing it only changes the local copy, not the array.
- Looping over a collection that might be null — the hidden iterator() call throws a NullPointerException before the first iteration, so return an empty list instead of null.
- Trying to use a Map directly in a for-each loop; Map is not Iterable, so loop over entrySet(), keySet() or values().
- Needing the current index inside the loop and having no clean way to get it without falling back to an indexed for loop.
- Adding or removing elements from a List while iterating it with for-each, which throws a ConcurrentModificationException at runtime.
- Assuming for-each can iterate in reverse order — it always moves forward from the first element to the last.
Exercise
Find the largest value in an array using a for-each loop, without using any library method.
Expected output: 89
public class LargestValue {
public static void main(String[] args) {
int[] scores = {12, 45, 7, 89, 23};
// TODO: find the largest value with a for-each loop
System.out.println(largest);
}
}
Show hints
- Start by assuming the first element is the largest, then compare every element against it.
- The loop reads as "for each score in scores":
for (int score : scores).
Show solution
public class LargestValue {
public static void main(String[] args) {
int[] scores = {12, 45, 7, 89, 23};
int largest = scores[0];
for (int score : scores) {
if (score > largest) {
largest = score;
}
}
System.out.println(largest); // 89
}
}
Quick quiz
1. Given int[] nums = {1, 2, 3};, what does the array contain after for (int n : nums) { n = n * 2; }?
- A. {2, 4, 6}
- B. {0, 0, 0}
- C. {1, 2, 3}
- D. It does not compile
Show answer
C. n is a copy of each element. Assigning to it changes only the local variable, not the array.
2. What happens when you call list.remove(item) on an ArrayList inside a for-each loop over that same list?
- A. The item is removed safely
- B. The loop restarts
- C. It does not compile
- D. It usually throws ConcurrentModificationException
Show answer
D. The loop uses an iterator that detects the list was changed behind its back and throws ConcurrentModificationException. Use Iterator.remove() or removeIf() instead.
3. What must your own class implement to be usable in a for-each loop?
- A. Iterable
- B. Comparable
- C. Serializable
- D. Cloneable
Show answer
A. for-each works on arrays and on any object that implements Iterable, which supplies an Iterator.
Interview questions
What are the limitations of the for-each loop?
Show answer
You have no index, so you cannot easily tell the position of an element, iterate backwards, skip elements, or walk two arrays in step. You cannot replace an element of an array through the loop variable, and you cannot safely remove from the collection you are iterating. When any of those is needed, use an indexed for loop or an explicit Iterator.
How does the for-each loop work internally?
Show answer
It is compiler shorthand. For an array, the compiler generates an ordinary indexed loop from 0 to length. For anything else, it calls iterator() on the Iterable and loops with hasNext() and next(). That hidden iterator is why modifying a collection inside the loop is detected.
Key Points to Remember
- for-each works on arrays and any type implementing Iterable, without managing an index manually.
- The loop variable receives a copy of each element; reassigning it never changes the underlying array or collection.
- for-each has no built-in index access and always iterates forward only.
- Modifying a collection's structure while iterating it with for-each can throw ConcurrentModificationException.
- Internally, for-each over an array compiles to an indexed loop, and over an Iterable to an iterator loop using hasNext() and next().
- Any class implementing Iterable can be used in for-each; to remove while looping, use Iterator.remove() or removeIf().
Practice in the playground
Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.
Run the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.
Written by
WebNest Studio Engineering Team
Practical lessons from developers working with Java, Python, React, databases and production systems.
Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering