Topic 41 of 119 4. Control Flow in Java Interactive Tutorial

Java Enhanced for Loop: Iterating Through Arrays and Collections

12 mins read Last updated: 22 Aug 2026 21,950 views

Direct Answer & Core Concept

The enhanced for loop, usually called the for-each loop, is a simplified way to walk through an array or a collection. It arrived in Java 5 and it exists for one reason: to remove the three things you get wrong most often with an indexed loop, which are the starting index, the ending bound and the increment. The syntax looks nothing like a normal for loop, and that is deliberate.

Main.java
Run Online
for (String name : names) {
    System.out.println(name);
}

Read the colon as the word in. It says: for each String in names, put it into name. There is no counter, no index and no chance of an off-by-one error, because there is nothing to get out of bounds. That is why it is the safest loop in Java and the one you should reach for by default whenever you are simply visiting every element. The critical thing to understand is that it is read-only in two different ways. You cannot change the size of the collection while iterating it, and you cannot assign a new value to the loop variable to change the element. What you can do is modify the object the element points at, such as calling a setter on it, because that changes the object rather than the reference. Knowing that boundary is what lets you pick the right loop with confidence.

Detailed Explanation & Mechanics

1) The Syntax, and How to Read It

Main.java
Run Online
for (Type element : collection) {
    // use element
}

There are two parts either side of the colon, and only one of them is the thing you already know.

PartWhat it is
Left of the colonA local variable to hold each element. Declared fresh inside the loop.
The colonRead it as the word in.
Right of the colonThe array or collection to walk through.
Main.java
Run Online
String[] cities = {
    "Dhaka", "London", "Tokyo"
};
for (String city : cities) {
    System.out.println(city);
}// prints
// Dhaka
// London
// Tokyo

Compare that with the indexed version, and count how many things you no longer have to get right.

Main.java
Run Online
for (int i = 0;
i < cities.length;
i++) {
    System.out.println(cities[i]);
}


Diagram of the for each loop syntax broken into three labelled parts: the loop variable, the colon, and the collection being traversed
Three parts, and the colon reads as the word in.

2) The Three Mistakes It Removes

This is the reason to prefer it, so it is worth being concrete about what it deletes.

Indexed for loopWhat can go wrongFor-each
int i = 0Starting at 1 or 2 and silently skipping an element.Not applicable, there is no start.
i < cities.lengthUsing <= throws, using < alone is easy to mistype.Not applicable, there is no bound.
i++Forgetting it means an infinite loop.Not applicable, it cannot be forgotten.

That is the entire argument for the for-each loop. Three sources of bugs, all removed, and the result is code that says what you mean rather than how to do it.

3) What It Works On

The for-each loop works on two things: arrays, and anything that implements Iterable, which is the interface that gives a class the ability to be used in a for-each loop.

Main.java
Run Online
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
int[] numbers = {
    1, 2, 3
};
String[] words = {
    "a", "b"
};
double[] prices = {
    1.5, 2.5
};
List<String> list = new ArrayList<>();
Set<String> set = new HashSet<>();
Map<String, Integer> map = new HashMap<>();
for (int n : numbers) {
} // arrays of any primitive type
for (String w : words) {
}for (double p : prices) {
}for (String s : list) {
} // any List
for (String s : set) {
} // any Set
for (Map.Entry<String, Integer> e : map.entrySet()) {
} // a Map, via entrySet

The line worth pausing on is the last one. A Map cannot be traversed directly, because it holds key-value pairs rather than single values. You iterate over map.entrySet() and each item is a Map.Entry giving you both halves.

Main.java
Run Online
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
    System.out.println(entry.getKey() + " scored " + entry.getValue());
}

If you only need the keys, iterate map.keySet(). If you only need the values, iterate map.values(). Both are clearer than looping over entries and discarding half of each one.

4) The Two Rules You Cannot Break

Rule one: you cannot add or remove elements while the for-each loop is running. It throws ConcurrentModificationException.
Rule two: you cannot assign a new value to the loop variable to change the element in the collection.

Rule One, Changing the Size

Main.java
Run Online
import java.util.ArrayList;
import java.util.List;
List<String> names = new ArrayList<>(List.of("Alex", "Sam", "Robin"));
for (String name : names) {
    if (name.equals("Sam")) {
        names.add("Jordan");
        // throws ConcurrentModificationException
    }
}

The reason is not arbitrary. The for-each loop holds an iterator over the collection, and modifying the structure underneath an active iterator leaves that iterator pointing at a position that no longer means what it did. Rather than let that produce silently wrong results, Java throws.

The fix is to iterate over a copy, or to use an explicit iterator which is designed for exactly this job.

Main.java
Run Online
// Safe: modify a copy, iterate the copy
for (String name : new ArrayList<>(names)) {
    if (name.equals("Sam")) {
        names.add("Jordan");
    }
}// Or remove safely, which does not change the size mid-iteration
names.removeIf(n -> n.equals("Sam"));

Rule Two, Assigning the Loop Variable

Main.java
Run Online
int[] numbers = {
    1, 2, 3
};
for (int n : numbers) {
    n = 99;
    // legal Java, but changes nothing
}System.out.println(numbers[0]);
// still 1

That line looks like it should work and it does not. Each iteration the loop creates a new copy of the element into n. Assigning to n changes that copy, and the copy is thrown away at the end of the iteration. The array is untouched.

What you can do is modify the object the element points at. This is the distinction that trips people up.

Main.java
Run Online
class Box {
    int value;
    Box(int value) {
        this.value = value;
    }
}final int FIRST = 1;
final int SECOND = 2;
final int ZERO = 0;
Box first = new Box(FIRST);
Box second = new Box(SECOND);
Box[] boxes = {
    first, second
};
for (Box b : boxes) {
    b.value = 99;
    // WORKS: changes the object behind the reference
}for (Box b : boxes) {
    System.out.println(b.value);
    // 99, 99
}// Replacing the reference in the array needs an indexed loop
for (int i = 0;
i < boxes.length;
i++) {
    boxes[i] = new Box(ZERO);
}


Diagram showing that the for each loop cannot change the size of a collection but can modify the objects that elements point to
The size is fixed for the duration. Modifying the objects inside it is fine.

5) When to Use for Each, and When Not To

SituationUseWhy
Visiting every elementfor-eachNo index, so no off-by-one possible.
You need the positionIndexed forThe for-each loop gives you no index.
Iterating backwardsIndexed forfor-each only goes forwards.
Skipping every other elementIndexed forYou cannot count without an index.
Replacing elementsIndexed forAssigning the loop variable changes nothing.
Adding or removing itemsIterator or removeIfDirect modification throws.
Printing or loggingfor-eachThe clearest possible expression of intent.

A useful habit is to write the for-each version first whenever the task is simply "do this to each item". If you then find yourself needing the index, switch to the indexed form knowingly, rather than starting with the indexed form and treating for-each as an optimisation you cannot afford.

Main.java
Run Online
// Readable: printing a report line for every sale
for (Sale sale : sales) {
    System.out.println(sale.getDate() + "  " + sale.getTotal());
}// Needs the index? Now switch, on purpose
for (int i = 0;
i < sales.size();
i++) {
    System.out.println("row " + i + " total " + sales.get(i).getTotal());
}

6) What Happens Under the Hood

It is worth knowing that the for-each loop is not magic, and the compilation is different depending on what you are iterating.

IteratingBecomes roughly
An arrayA plain indexed for loop, with the length read once up front.
A CollectionA call to iterator(), then hasNext() and next() each pass.
Main.java
Run Online
// What you write
for (String city : cities) {
    System.out.println(city);
}// Roughly what the compiler produces for an array
for (int i = 0;
i < cities.length;
i++) {
    String city = cities[i];
    System.out.println(city);
}

This explains two behaviours you may have already noticed. It explains why a for-each over a collection throws when you modify the structure, because an iterator is what is underneath. And it explains why the for-each over an array is not slower than an indexed loop, since it compiles to the same thing.

One subtlety: for an array the length is evaluated once, before the loop starts. If something inside the loop changes the array reference itself, the loop keeps using the original one. This is a real but rare edge case, and it is a good reason to prefer a collection when the structure is being modified.

7) Common Mistakes

MistakeSymptomFix
Adding or removing during the loopConcurrentModificationException at run time.Iterate a copy, or use an iterator or removeIf.
Assigning to the loop variableNo error, and no change either.Use an indexed for loop to replace elements.
Expecting an indexCompile error, there is no index variable.Switch to an indexed for loop.
Iterating a Map directlyCompile error, a Map is not Iterable.Use entrySet(), keySet() or values().
Reusing the variable name outsideCompile error, the variable is scoped to the loop.Declare your own variable before the loop if you need it after.
Wrong element type declaredCompile error on a type mismatch.Declare the variable with the collection's element type.


Infographic of six common for each loop mistakes each shown with the wrong and the corrected code
Six for-each mistakes. The first two fail silently, which is why they are the dangerous ones.

The second row is the one to remember. Assigning to the loop variable is not an error in any sense, it just quietly does nothing, and it is a common instinct coming from other languages where the loop variable is a real reference.

Frequently Asked Questions

What does the colon in a for-each loop mean?


Read it as the word in. The statement for (String city : cities) means for each String in cities, place it into the variable city. The left side is a local variable, the right side is the array or collection.

Can I modify a collection inside a for-each loop?


Not its size. Adding or removing elements throws ConcurrentModificationException. You may however modify the objects the elements point at, such as calling a setter, because that changes the object rather than the structure. To change the size, iterate over a copy or use an iterator.

Why does assigning to the loop variable change nothing?


Because each iteration copies the element into the loop variable. Assigning to it changes that temporary copy, which is discarded at the end of the iteration. The array or collection is untouched. To replace an element you need an indexed for loop.

Can I iterate backwards with a for-each loop?


No, it only traverses forwards from the first element. Use an indexed for loop starting at size minus one and counting down if you need reverse order.

Does a for-each loop work with a Map?


Not directly, because a Map holds key-value pairs. Iterate map.entrySet() for both parts, map.keySet() for keys only, or map.values() for values only. Each entry gives you getKey and getValue.

Is a for-each loop slower than an indexed for loop?


No. For an array the compiler produces essentially the same indexed loop. For a collection it uses an iterator, which has a small overhead per element but buys you safety and readability, and that trade is almost always worth it.

Can I use a for-each loop on a two-dimensional array?


Yes, but each element is itself an array, so you need a nested loop. The outer for-each gives you a row and the inner one walks that row. This is the standard way to print a matrix.

Runnable Code Example: Java Enhanced for Loop

Java 17+
Main.java
Run Online
// Demonstrates the Java enhanced for loop.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EnhancedForDemo {
    // A simple mutable object, to show rule two clearly.
    static class Box {
        String label;
        Box(String label) {
            this.label = label;
        }
    } public static void main(String[] args) {
        String[] cities = {
            "Dhaka", "London", "Tokyo"
        };
        int[] scores = {
            88, 74, 95
        };
        List<String> names = new ArrayList<>(List.of("Alex", "Sam", "Robin"));
        Map<String, Integer> totals = new HashMap<>();
        totals.put("Alex", 120);
        totals.put("Sam", 95);
        totals.put("Robin", 140);
        // 1) THE BASICS: no index, no bound, no increment to get wrong.
        System.out.println("cities:");
        for (String city : cities) {
            System.out.println("  " + city);
        } // 2) IT WORKS ON ANY PRIMITIVE ARRAY TOO.
        int best = scores[0];
        for (int score : scores) {
            if (score > best) {
                best = score;
            }
        } System.out.println("highest score: " + best);
        // 3) IT WORKS ON ANY COLLECTION, NOT JUST ARRAYS.
        System.out.println("names:");
        for (String name : names) {
            System.out.println("  " + name);
        } // 4) A MAP IS NOT ITERABLE ITSELF. Go via entrySet()
        //    when you need both the key and the value.
        System.out.println("totals:");
        for (Map.Entry<String, Integer> entry : totals.entrySet()) {
            System.out.println("  " + entry.getKey() + " -> " + entry.getValue());
        } // 5) RULE TWO, PART ONE: assigning the loop variable
        //    changes nothing, because each value is a fresh copy.
        int[] numbers = {
            1, 2, 3
        };
        for (int n : numbers) {
            n = 99;
            // legal, and completely ignored
        } System.out.println("after n = 99, first element is still " + numbers[0]);
        // 6) RULE TWO, PART TWO: you CAN modify the object behind
        //    the reference, because that is not the same thing.
        Box[] boxes = {
            new Box("first"), new Box("second")
        };
        for (Box box : boxes) {
            box.label = box.label.toUpperCase();
        } System.out.println("labels uppercased: " + boxes[0].label + ", " + boxes[1].label);
        // 7) RULE ONE: changing the SIZE mid-loop throws.
        //    This line is left commented because it would crash.
        // for (String name : names) {
        //     names.add("Jordan");       // ConcurrentModificationException
        // }
        // The safe alternatives, shown uncommented:
        List<String> growable = new ArrayList<>(names);
        growable.add("Jordan");
        System.out.println("copy grew safely to " + growable.size() + " items");
        // 8) WHEN YOU NEED THE INDEX, SWITCH DELIBERATELY.
        //    This is not a limitation to work around, it is a signal.
        for (int i = 0;
        i < names.size();
        i++) {
            System.out.println("  " +(i + 1) + ". " + names.get(i));
        } // 9) A TWO-DIMENSIONAL ARRAY NEEDS A NESTED for-each.
        int[][] grid = {
{
                1, 2, 3
            }, {
                4, 5, 6
            }
        };
        System.out.println("grid:");
        for (int[] row : grid) {
            // each element is itself an array
            for (int value : row) {
                System.out.print(value + " ");
            } System.out.println();
        }
    }
}/*
    ACTUAL OUTPUT:

        cities:
          Dhaka
          London
          Tokyo
        highest score: 95
        names:
          Alex
          Sam
          Robin
        totals:
          Robin -> 140
          Sam -> 95
          Alex -> 120
        after n = 99, first element is still 1
        labels uppercased: FIRST, SECOND
        copy grew safely to 4 items
1. Alex
2. Sam
3. Robin
        grid:
        1 2 3
        4 5 6

    THE FOUR THINGS TO REMEMBER
    1) Read the colon as the word in: for (X x : xs) means
       for each X in xs, put it into x.
    2) It removes the three things indexed loops get wrong: the
       start index, the ending bound and the increment.
    3) You cannot change the SIZE of a collection while iterating
       it, and you cannot assign the loop variable to change an
       element. You CAN modify the object behind the reference.
    4) Reach for it by default. Switch to an indexed for loop the
       moment you genuinely need the position.
*/

Common Java Technical Interview Questions & Answers

Interview Prep
Q1: What does the colon in a for-each loop mean and what are its two parts?\nA1: Read it as the word in. The left side is a local variable that holds each element in turn, and the right side is the array or collection being traversed, so for (String city : cities) means for each String in cities, place it into city.\nQ2: Why is a for-each loop safer than an indexed for loop?\nA2: Because it removes the three things indexed loops most often get wrong: the starting index, the ending bound and the increment. With no index there is no possibility of an off-by-one error or an ArrayIndexOutOfBoundsException.\nQ3: Can you add or remove elements while a for-each loop is running?\nA3: No, it throws ConcurrentModificationException. The loop holds an iterator over the structure, and changing the size underneath it would leave that iterator in an invalid position. Iterate a copy, or use an iterator or the removeIf method instead.\nQ4: Why does assigning to the loop variable change nothing?\nA4: Because each iteration copies the element into the loop variable, and that temporary copy is discarded at the end of the pass. Assigning to it changes only the copy. You can still modify the object the element points at, such as calling a setter, because that changes the object rather than the reference.\nQ5: How do you iterate a Map with a for-each loop?\nA5: A Map is not itself Iterable. Iterate map.entrySet() for both key and value, map.keySet() for keys only, or map.values() for values only. Each entry exposes getKey and getValue.\nQ6: Can you iterate backwards with a for-each loop?\nA6: No, it only traverses forwards. Use an indexed for loop starting at size minus one and counting down when reverse order is required.\nQ7: Is a for-each loop slower than an indexed for loop?\nA7: No. For an array the compiler produces essentially the same indexed loop. For a collection it uses an iterator, which costs a little per element but removes a whole class of bugs, and that trade is almost always worth taking.\nQ8: When should you deliberately choose an indexed for loop instead?\nA8: When you need the index, want to iterate backwards, want to skip elements, or need to replace elements in the structure. Needing the index is not a limitation to work around but a clear signal that the indexed form is the right tool.

Key Takeaways, Best Practices & Clean Code Rules

Java Best Practice & Production Rules

Reach for the for-each loop by default whenever the task is simply doing something to every element, and switch to an indexed for loop only when you genuinely need the position.\nTreat needing the index as a signal rather than an obstacle, since the indexed form is clearer for anything that involves positions, reverse order or skipping.\nNever add or remove elements while a for-each loop is running, and instead iterate a copy, use an explicit iterator, or call removeIf which is designed for safe removal.\nDo not expect assigning to the loop variable to change an element, because it only changes a temporary copy, and use an indexed loop when you need to replace elements.\nDo modify the objects that elements point at when you need to change their state, since calling a setter through the loop variable works correctly and is often what you actually want.\nUse entrySet, keySet or values when iterating a Map rather than trying to iterate the Map directly, and choose keySet or values when you only need one half of each pair.\nDeclare the loop variable with the collection actual element type, since a mismatch is a compile error that is easy to fix now and annoying to trace later.\nDo not try to reuse the loop variable after the loop, because it is scoped to the loop, and declare a separate variable beforehand if you need the final value.\nWhen the collection is being modified during the work, prefer a collection over a raw array, since the array form captures the length once at the start.\nRead for-each code as a sentence, for each sale in sales, so if the line does not read naturally in English the loop is probably the wrong shape for the job.
We value your privacy & transparency

OperateTools uses cookies and local storage to ensure basic tool functionality, preserve preferences, and analyze aggregated traffic. We never sell your personal data or index your document files. Learn more in our Privacy Policy.