Question

How the Enhanced for-each Loop Works in Java

javaforeachsyntactic-sugar

Question

Given the following Java code:

List<String> someList = new ArrayList<>();
someList.add("monkey");
someList.add("donkey");
someList.add("skeleton key");

for (String item : someList) {
    System.out.println(item);
}

What is the equivalent loop written without Java's enhanced for-each syntax?

Also, why do beginners often run into problems when they try to modify the original collection by assigning to the loop variable inside a for-each loop?

Short Answer

By the end of this page, you will understand how Java's enhanced for-each loop works, what code it is roughly equivalent to under the hood, why assigning to the loop variable does not update the original list, and when to use a regular for loop or an Iterator instead.

Concept

Java's enhanced for-each loop is a simpler way to iterate through arrays and collections.

Instead of manually managing an index or an Iterator, you write:

for (String item : someList) {
    System.out.println(item);
}

This means:

  • take each element from someList
  • store it temporarily in item
  • run the loop body
  • repeat until there are no more elements

For a List, the loop is conceptually similar to using an Iterator:

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

For an array, it behaves more like stepping through indexes from 0 to length - 1.

Why this matters:

  • It makes code shorter and easier to read.
  • It reduces mistakes involving indexes.
  • It is ideal when you only need to read values.

But it also has an important limitation:

  • the loop variable is just a local variable for the current element
  • reassigning that variable does not replace the element inside the collection

So this:

for (String item : someList) {
    item = item.toUpperCase();
}

does not update the list contents. It only changes what the local variable item refers to during that iteration.

Mental Model

Think of a for-each loop like reading names from a printed attendance sheet.

A helper points at each name one at a time and says, "Here is the current one." You can read the name, print it, or use it in calculations.

But if you write a different name on your own notepad, you have not changed the attendance sheet itself.

In this analogy:

  • the collection is the attendance sheet
  • the loop variable is the name currently handed to you
  • assigning a new value to the loop variable is like changing your note, not the original sheet

If you actually want to update the original list, you need a way to write back into the list, such as:

  • using an index with list.set(index, value)
  • using a ListIterator
  • replacing the whole collection content in another way
Take Quiz

Syntax and Examples

Basic syntax

for (Type variable : collectionOrArray) {
    // use variable
}

Example with a list:

List<String> animals = new ArrayList<>();
animals.add("monkey");
animals.add("donkey");
animals.add("skeleton key");

for (String animal : animals) {
    System.out.println(animal);
}

This prints:

monkey
donkey
skeleton key

Equivalent form using an Iterator

For most collections, the enhanced for-each loop is roughly equivalent to:

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

Equivalent form using an index

Because this example uses a List, you could also write:

for (int i = 0; i < animals.size(); i++) {
    String animal = animals.get(i);
    System.out.println(animal);
}

This is not exactly how for-each is implemented for every collection, but it produces the same result for a List.

Example of a common misunderstanding

for (String animal : animals) {
    animal = animal.toUpperCase();
}

System.out.println(animals);

Output:

[monkey, donkey, skeleton key]

Why? Because animal is only a local variable. Reassigning it does not replace the element in the list.

Correct way to update list elements

for (int i = 0; i < animals.size(); i++) {
    animals.set(i, animals.get(i).toUpperCase());
}

System.out.println(animals);

Output:

[MONKEY, DONKEY, SKELETON KEY]

Step by Step Execution

Consider this code:

List<String> items = List.of("monkey", "donkey", "skeleton key");

for (String item : items) {
    System.out.println(item);
}

You can think of it as if Java does this:

Iterator<String> it = items.iterator();
while (it.hasNext()) {
    String item = it.next();
    System.out.println(item);
}

Step by step:

  1. items.iterator() creates an iterator positioned before the first element.
  2. it.hasNext() checks whether another element exists.
  3. it.next() returns the next element, such as "monkey".
  4. That value is assigned to the loop variable item.
  5. System.out.println(item); prints the current value.
  6. The loop repeats for "donkey".
  7. The loop repeats for "skeleton key".
  8. When hasNext() returns false, the loop stops.

Now look at this variation:

List<String> items = new ArrayList<>();
items.add("monkey");
items.add("donkey");

for (String item : items) {
    item = item.toUpperCase();
}

System.out.println(items);

Step by step:

  1. First iteration: item gets "monkey".
  2. item = item.toUpperCase(); changes the local variable item to refer to "MONKEY".
  3. The list still contains "monkey" because nothing wrote back to items.
  4. Second iteration: item gets "donkey".
  5. item becomes "DONKEY" locally.
  6. The list still contains "donkey".
  7. Printing items shows the original values unchanged.

Real World Use Cases

Enhanced for-each loops are common when you want to read each element in a sequence without worrying about indexes.

Common uses

  • Printing log messages from a list
  • Validating input values one by one
  • Summing numbers in an array or collection
  • Rendering UI data such as product names or menu items
  • Processing API results returned as lists

Example: validating user input

List<String> usernames = List.of("alice", "", "charlie");

for (String username : usernames) {
    if (username.isBlank()) {
        System.out.println("Invalid username found");
    }
}

Example: summing values

int[] numbers = {10, 20, 30};
int total = 0;

for (int number : numbers) {
    total += number;
}

System.out.println(total); // 60

When not to use it

Avoid for-each when you need to:

  • know the current index
  • replace elements in a list
  • remove elements during iteration without proper iterator methods
  • skip around manually in the collection
Take Quiz

Real Codebase Usage

In real Java projects, developers use enhanced for-each loops mainly for read-only traversal.

Common patterns

1. Read and process each item

for (Order order : orders) {
    sendConfirmationEmail(order);
}

2. Validation with guard clauses

for (String email : emails) {
    if (email == null || email.isBlank()) {
        throw new IllegalArgumentException("Email cannot be empty");
    }
}

3. Aggregation

double total = 0;
for (Invoice invoice : invoices) {
    total += invoice.getAmount();
}

When developers switch to other tools

Use an index-based loop when replacing list elements

for (int i = 0; i < names.size(); i++) {
    names.set(i, names.get(i).trim());
}

Use an Iterator when removing safely during iteration

Iterator<String> it = names.iterator();
while (it.hasNext()) {
    if (it.next().isBlank()) {
        it.remove();
    }
}

Use streams for transformations

List<String> upper = names.stream()
    .map(String::toUpperCase)
    .toList();

In production code, choosing the loop style depends on the task:

  • read only -> for-each
  • update by position -> index loop
  • remove while iterating -> Iterator
  • build transformed data -> stream operations

Common Mistakes

1. Thinking assignment updates the collection

Broken code:

for (String item : items) {
    item = "changed";
}

Problem:

  • This only changes the local loop variable.
  • The list stays the same.

Fix:

for (int i = 0; i < items.size(); i++) {
    items.set(i, "changed");
}

2. Removing elements directly from the collection during for-each

Broken code:

for (String item : items) {
    if (item.isBlank()) {
        items.remove(item);
    }
}

Problem:

  • This can cause ConcurrentModificationException.

Fix:

Iterator<String> it = items.iterator();
while (it.hasNext()) {
    if (it.next().isBlank()) {
        it.remove();
    }
}

3. Expecting an index inside for-each

Broken thinking:

  • for-each gives you each value, not its numeric position.

Fix:

Use a regular loop if you need the index:

for (int i = 0; i < items.size(); i++) {
    System.out.println(i + ": " + items.get(i));
}

4. Confusing object mutation with variable reassignment

This code can work:

for (StringBuilder sb : builders) {
    sb.append("!");
}

Why?

  • You are mutating the object that sb refers to.
  • You are not reassigning sb itself.

This code does not replace list elements:

for (StringBuilder sb : builders) {
    sb = new StringBuilder("new");
}

Why?

  • Now you are only changing the local variable.

5. Modifying immutable collections

Broken code:

List<String> items = List.of("a", "b");
items.set(0, "x");

Problem:

  • List.of(...) creates an immutable list.

Fix:

List<String> items = new ArrayList<>(List.of("a", "b"));
items.set(0, "x");

Comparisons

ApproachBest forCan access index?Can replace elements easily?Can remove safely while iterating?
Enhanced for-eachReading elementsNoNoNo
Index-based for loopLists and arrays when position mattersYesYesSometimes, but must be careful
IteratorSafe traversal with removalNoNot directlyYes, with remove()
ListIteratorTraversing and updating listsPartialYesYes

Enhanced for-each vs regular for

for (String item : items) {
    System.out.println(item);
}
  • simpler
  • more readable
  • no index management
for (int i = 0; i < items.size(); i++) {
    System.out.println(items.get(i));
}
  • useful when you need i
  • useful for set(i, value)

for-each vs Iterator

for (String item : items) {
    System.out.println(item);
}
  • best for simple reads
Iterator<String> it = items.iterator();
while (it.hasNext()) {
    String item = it.next();
    if (item.isBlank()) {
        it.remove();
    }
}
  • best when removing during iteration
  • exposes iteration mechanics directly
Take Quiz

Cheat Sheet

Enhanced for-each syntax

for (Type variable : collectionOrArray) {
    // use variable
}

Equivalent for a collection

for (Iterator<Type> it = collection.iterator(); it.hasNext(); ) {
    Type variable = it.next();
    // use variable
}

Equivalent for a list if you want indexes

for (int i = 0; i < list.size(); i++) {
    Type variable = list.get(i);
}

Key rules

  • Works with arrays and Iterable collections.
  • The loop variable is a local variable for the current element.
  • Reassigning the loop variable does not update the collection.
  • Use list.set(i, value) to replace elements.
  • Use Iterator.remove() to remove safely while iterating.

Remember

for (String s : list) {
    s = s.toUpperCase(); // does not change list
}
for (int i = 0; i < list.size(); i++) {
    list.set(i, list.get(i).toUpperCase()); // changes list
}

Edge cases

  • List.of(...) is immutable.
  • Modifying the collection structure during for-each usually causes errors.
  • Mutating the object itself is different from reassigning the loop variable.

FAQ

What is Java's enhanced for loop?

It is a shorter syntax for iterating through arrays and collections without manually writing an index or iterator.

Is a for-each loop the same as a normal for loop?

Not exactly. It can produce the same result, but for collections it is conceptually based on an Iterator, not always an index.

Why doesn't assigning to the loop variable change the list?

Because the loop variable is only a temporary local variable holding the current element reference or value.

Can I remove items inside a Java for-each loop?

Not safely by calling list.remove(...) directly. Use an Iterator and its remove() method.

Can I modify objects inside a for-each loop?

Yes. If the element is a mutable object, you can change the object's internal state. What you cannot do is replace the collection element just by reassigning the loop variable.

When should I use a regular for loop instead?

Use a regular for loop when you need the index or need to replace elements in a list.

Does for-each work on arrays too?

Yes. It works on both arrays and collections that implement Iterable.

Take Quiz

Mini Project

Description

Build a small Java program that displays a list of task names, then creates an updated version of those tasks in uppercase. This project demonstrates the difference between reading with for-each and actually changing list data with an index-based loop.

Goal

Learn when for-each is appropriate and when you must use a different loop to update list contents.

Requirements

Create a list of at least three task names. Print all tasks using an enhanced for-each loop. Attempt to uppercase tasks by assigning to the for-each loop variable. Show that the original list is unchanged. Use an index-based loop to update the list correctly. Print the final updated list.

Take Quiz

Keep learning

Related questions

View more