Funny error with Java’s extended for-loop

Java 5 introduced the enhanced for-loop – or for-each loop – which simplifies iterating over many types of collections. Have a look at this simple piece of code and tell me what’s wrong:


import java.util.HashSet;
import java.util.Set;

public class Demo {
	public static void main(String[] args) {
		Set set = new HashSet();
		set.add("Value 1");
		set.add("Value 2");
		set.add("Value 3");
		set.add("Value 4");
		set.add("Value 5");
		synchronized (set) {
			for (String tEntry : set) {
				if (tEntry.endsWith("3")) {
					System.out.println("3 has to go");
				} else {
					System.out.println(tEntry + " may stay");

When I wrote this I naively expected something like this to be written out(the order of the iteration is undefined for a HashSet, but bear with me:

Value 5 may stay
Value 2 may stay
3 has to go
Value 4 may stay
Value 1 may stay

Admit it, this is what you would have guessed, too! But instead this code throws an exception! The problem occurs in line 16 and looks like this:

Value 5 may stay
3 has to go
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(
at java.util.HashMap$

Any clearer now? Well, turns out that the hidden magic behind some of the Java 5 features (this time the part that makes the enhanced for-loop possible) promotes  some kinds of problems I – in this case – would most probably have seen and avoided had I used the old-style Iterator approach.

Under the hood there still is an Iterator at work, but the syntactic sugar in the example above hides this detail from you. At compile time the above will be translated into the old-style iteration for you.

Because now there is no obvious Iterator instance, it is easy to forget this important part of the JDK API documentation for “ConcurrentModificationException”:

Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will thow [sic] this exception

This is exactly what happens here. The Iterator is still there, even if it does not appear in the source. It’s hasNext() and next() methods are used to loop through the elements of the collection. Once “Value 3” has been found, the code removes it from the Set directly, bypassing the Iterator. The next time it is used – which is when the next element is prepared to be passed into the loop body – it detects that the underlying collection has been independently changed and obeys its fail-fast policy, producing the exception above.

So in this case, even without the classical problem of multiple threads sharing mutable state, there are two parties modifying the collection. To solve the problem, we have to fall back to the classical looping code:

String tEntry;
for (Iterator iter = set.iterator(); iter.hasNext(); ) {
	tEntry =;
	if (tEntry.endsWith("3")) {
		System.out.println("3 has to go");
	} else {
		System.out.println(tEntry + " may stay");

This in fact produces the desired output, however the code looks somewhat more cluttered than before.

Proves (again) that despite lots of eye-candy, syntactic sugar or whatever it is called you still need to understand what is going on under the covers most of the time. A novice programmer might get really confused about this...

Technorati Tags: ,,


Byju Joy said…
For-each loop doesn't allow structural modification of the Collection you are looping through. Set.remove() causes structural modification to Collection/Set.

For-each loop is my favourite among Java5 additions.

Popular posts from this blog

SAXParseException: -1:-1: Premature End Of File - Misleading error

Can't start server: Bind on TCP/IP port: No such file or directory

FindBugs - Writing custom detectors (Part 1)