As we can see in spec http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.14.2
java foreach (= enhanced for) statement uses iterator inside.
Let's to small check with javac and jad:
Here I have a class with a method:
public void bar() {
Collection<Object> c = Collections.synchronizedList(new ArrayList<Object>());
for(Object cc : c) {
System.out.println(cc);
}
}
Than check compiled bytecode with jad:
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: java.java
public void bar()
{
Collection c = Collections.synchronizedList(new ArrayList());
Object cc;
for(Iterator i$ = c.iterator(); i$.hasNext(); System.out.println(cc))
cc = i$.next();
}
Here we can see foreach statement was implemented as iterator. For a collection that was created with java.util.Collections#synchronized* method this would mean an external synchronization is required!
The right fix for it is to avoid using java.util.Collections#synchronized* in project at all.
For some reasons, it could be complicated to implement, this, one may need to workaround it.
The workarounds for it are obvious. For me the easiest is to add .toArray() to the collection as the method is synchronized in proxies from java.util.Collections#synchronized*:
public void bar() {
Collection<Object> c = Collections.synchronizedList(new ArrayList<Object>());
for(Object cc : c.toArray()) {
System.out.println(cc);
}
}
Let's check jad output to be sure:
public void bar()
{
Collection c = Collections.synchronizedList(new ArrayList());
Object arr$[] = c.toArray();
int len$ = arr$.length;
for(int i$ = 0; i$ < len$; i$++)
{
Object cc = arr$[i$];
System.out.println(cc);
}
}
I also added a feature request for IDEA to support this case:
http://youtrack.jetbrains.net/issue/IDEA-71662 comments powered by Disqus