Java Collection classes are fail-fast which means that if the
Collection will be changed while some thread is traversing over it
using iterator, the iterator.next()
will throw a ConcurrentModificationException
.
This situation can come in case of multithreaded as well as single
threaded environment. - www.javacodegeeks.com
You can't modify a List
in a for/each
loop, which is syntactic sugar around the Iterator
as an implementation detail. You can only safely call .remove()
when using the Iterator
directly.
Note that Iterator.remove is the only safe way to modify a collection
during iteration; the behavior is unspecified if the underlying
collection is modified in any other way while the iteration is in
progress. - Java Collections
Tutorial
Calling .add()
inside the for/each
loop modifies the contents, and the Iterator
that is used behind the scenes sees this and throws this exception.
A more subtle concern is the that the second way you list, the .size()
is increasing every time you .add()
so you will end up processing all the things you .add()
, this could possibly cause an endless loop depending on what the input data is. I am not sure if this is what you desire.
Solution
I would create another ArrayList
and .add()
to it all the new things, and then after the loop, use .addAll()
on the original ArrayList
to combine the two lists together. This will make things explicit in what you are trying to do, that is unless your intention is process all the newly added things as you add them.
2014 Solution:
Always use Immutable
collections classes and build new Immutable
collection classes instead of trying to modify a single shared one. This is basically what my 2012 answer says but I wanted to make it more explicit.
Guava supports this very well, use ImmutableList.copyOf()
to pass around data.
Use Iterables.filter()
to filter out stuff into a new ImmutableList
, no shared mutable state, means no concurrency problems!
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…