Why is using the for-each loop on an ArrayList not working?
Solution 1
If a Collection
is modified while iterating over it, in most of the implementations, a ConcurrentModificationException
is thrown.
The "foreach" version:
for (String s : list) {
if (s.equals("a"))
list.remove(s);
}
internally is equivalent to
for(Iterator<String> i = list.iterator(); i.hasNext(); ) {
String s = i.next();
if (s.equals("a"))
list.remove(s);
}
As you can see, an interator is created, but the list is modified directly. The list
can only be modified by the iterator i
used to iterate over it.
Solution 2
Your link actually explains it pretty well:
In the foreach loop, compiler will make the .next() called after the operation of removing element, which caused the ConcurrentModificationException.
Solution 3
The for
uses an iterator internally. But you delete on the list directly => CME. The internal call to next
after the deletion will throw it because it finds the list modified.
In the example with while
, you delete through the iterator, which works fine.
Solution 4
When removing object from collections, use ITERATORS
Your code does not work because you are modifying the collection while looping over it. According to Oracle's javadoc the only safe way to do it is using iterators.
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.
Have a look at this for further infos
hamena314
"What have I done? What did I expect? What happened?" - Formula for writing a good question Effort for answer = readability + interestingness + effort for research shown
Updated on June 13, 2022Comments
-
hamena314 almost 2 years
I've stumbled upon this code, which throws a
ConcurrentModificationException
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d")); for (String s : list) { if (s.equals("a")) list.remove(s); }
If you add an Iterator and use a while-loop, the code works fine:
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d")); Iterator<String> iter = list.iterator(); while (iter.hasNext()) { String s = iter.next(); if (s.equals("a")) { iter.remove(); } }
I dont understand, why it is necessary, to use
Iterator<String>
in this case. Is it because of the ArrayList not having some sort of ability to get iterated, altough it is a subclass of Collection?Is it necessary to use the while-loop, or could you produce a version with a for-loop?
-
Fildor over 8 yearsyou are missing a call to
next
:) -
Tobías over 8 yearsYou're right, thanks!
-
hamena314 over 8 yearsBy
modifying
do you mean only remove or would adding elements have the same problem? -
Fildor over 8 years@hamena314 Not necessarily a Problem when adding, but you cannot be sure. Implementations may vary. So using the iterator to modify is the only guaranteed safe way.