Fundamentals 9 min read

Understanding Java for‑loop vs foreach: Traversal, Deletion, and Modification

This article explains how Java's traditional for loop and the enhanced foreach loop differ when iterating collections, how to correctly delete elements, why modifying collection elements directly with foreach fails, and how to safely modify element attributes using iterators or object methods.

Architect's Tech Stack
Architect's Tech Stack
Architect's Tech Stack
Understanding Java for‑loop vs foreach: Traversal, Deletion, and Modification

Java developers often wonder when to use the classic for loop versus the enhanced foreach (for‑each) loop. Both can iterate arrays and collections, but their behavior diverges when the loop body modifies the underlying data.

1) Traversing elements

Example code:

String[] array = {"1", "2", "3"};
for (String i : array) {
    System.out.println(i);
}

ArrayList
list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
for (String i : list) {
    System.out.println(i);
}

The output is the expected sequence of values. The compiled bytecode shows that array traversal is translated to an index‑based for loop, while collection traversal uses an Iterator .

2) Deleting elements

Using a classic for loop:

ArrayList
list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
log.info(list.toString());
for (int i = 0; i < list.size(); i++) {
    list.remove("222");
}
log.info(list.toString());

Result (log excerpt):

[111, 222, 333]
[111, 333]

The deletion succeeds because the loop controls the index directly.

Attempting the same with foreach throws a ConcurrentModificationException :

ArrayList
list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
log.info(list.toString());
for (String i : list) {
    list.remove("222");
}
log.info(list.toString());

Exception output:

java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
    ...

The failure occurs because the iterator detects that the collection’s internal modCount changed without using the iterator’s own remove() method.

Correct deletion with an iterator:

ArrayList
list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
log.info(list.toString());
Iterator
it = list.iterator();
while (it.hasNext()) {
    String next = it.next();
    if (next.equals("222")) {
        it.remove(); // iterator‑based removal
    }
}
log.info(list.toString());

Result:

[111, 222, 333]
[111, 333]

3) Modifying elements

With a classic for loop you can replace each element:

ArrayList
list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
log.info(list.toString());
for (int i = 0; i < list.size(); i++) {
    list.set(i, "444");
}
log.info(list.toString());

Result shows all entries become 444 . Using foreach to assign a new value to the loop variable does **not** modify the list because the variable holds a copy of the reference:

ArrayList
list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
log.info(list.toString());
for (String i : list) {
    i = "444"; // no effect on the list
}
log.info(list.toString());

The list remains unchanged.

4) Modifying element attributes with foreach

While you cannot replace the element itself, you can change its internal state because the loop variable still references the original object:

public class Student {
    private int age;
    private String name;
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public Student() {}
    public Student(int age, String name) { this.age = age; this.name = name; }
}

Student s1 = new Student(1, "huge");
Student s2 = new Student(1, "xiaoyao");
List
list = new ArrayList<>();
list.add(s1);
list.add(s2);
System.out.println(s1.getName()); // huge
System.out.println(s2.getName()); // xiaoyao
for (Student stu : list) {
    stu.setName("jingtian");
}
System.out.println(s1.getName()); // jingtian
System.out.println(s2.getName()); // jingtian

The names are updated because the objects themselves are mutated.

Summary

Both for and foreach can iterate arrays and collections, but for offers higher flexibility for complex operations such as element removal or replacement. foreach cannot delete or replace collection elements directly and will throw a ConcurrentModificationException when a removal is attempted without using the iterator’s remove() . However, both loops can modify the internal state of objects contained in the collection.

JavaIterationforeachfor loopCollectionmodification
Architect's Tech Stack
Written by

Architect's Tech Stack

Java backend, microservices, distributed systems, containerized programming, and more.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.