ConcurrentModificationException when adding inside a foreach loop in ArrayList
Java Collection classes are fail-fast which means that if the
Collection will be changed while some thread is traversing over it
using iterator, theiterator.next()
will throw aConcurrentModificationException
.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!
How to fix ConcurrentModificationException when using foreach to iterate over a List?
The exception results from adding an element to the models
List while iterating over it.
You have to change your logic. I suspect the logic of your inner loop is wrong anyway, and fixing it will also solve your problem. You probably want to search first if the List contains any element matching model
and modify it if found, and only add a new instance to the List if you don't find a match (i.e. after the loop is over).
Your inner loop would look like this:
if (models.isEmpty()) {
models.add(model);
} else {
boolean found = false;
for (ProjetVTO projetModel : models) {
if ((projetModel.getAnnee() == model.getAnnee()) && (projetModel.getPriorite().equals(model.getPriorite()))) {
projetModel.setNbillets(projetModel.getNbillets() + model.getNbillets());
found = true;
break;
}
}
if (!found) {
models.add(model);
}
}
or simply (you can eliminate the outer condition):
boolean found = false;
for (ProjetVTO projetModel : models) {
if ((projetModel.getAnnee() == model.getAnnee()) && (projetModel.getPriorite().equals(model.getPriorite()))) {
projetModel.setNbillets(projetModel.getNbillets() + model.getNbillets());
found = true;
break;
}
}
if (!found) {
models.add(model);
}
ConcurrentModificationException in foreach loop
In the second loop, it's the same reason - you are removing an element from the list.
To remove elements from a List
while looping through it, either use standard old-fashioned for loops:
for(int i=0;i<list.size();i++) {
and remove list items inside that loop or use a ListIterator
to iterate over the list.
Concurrent Modification Exception : adding to an ArrayList
ConcurrentModificationException occurs when you modify the list (by adding or removing elements) while traversing a list with Iterator
.
Try
List<Element> thingsToBeAdd = new ArrayList<Element>();
for(Iterator<Element> it = mElements.iterator(); it.hasNext();) {
Element element = it.next();
if(...) {
//irrelevant stuff..
if(element.cFlag){
// mElements.add(new Element("crack",getResources(), (int)touchX,(int)touchY));
thingsToBeAdd.add(new Element("crack",getResources(), (int)touchX,(int)touchY));
element.cFlag = false;
}
}
}
mElements.addAll(thingsToBeAdd );
Also you should consider enhanced for each loop as Jon suggested.
How to avoid java.util.ConcurrentModificationException when iterating through and removing elements from an ArrayList
Two options:
- Create a list of values you wish to remove, adding to that list within the loop, then call
originalList.removeAll(valuesToRemove)
at the end - Use the
remove()
method on the iterator itself. Note that this means you can't use the enhanced for loop.
As an example of the second option, removing any strings with a length greater than 5 from a list:
List<String> list = new ArrayList<String>();
...
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
String value = iterator.next();
if (value.length() > 5) {
iterator.remove();
}
}
why concurrent modification on foreach method but not on for loop
ForEach loop won't loop directly on your collection. It uses the iterator of your collection behind. you can see the iterator in your collections implementation.
From Arraylist source code
735
736 public Iterator<E> More ...iterator() {
737 return new Itr();
738 }
An optimized version of AbstractList.Itr
742
743 private class More ...Itr implements Iterator<E> {
744 int cursor; // index of next element to return
And your foreach loop equals to
for(Iterator<Integer> i = targets.iterator(); i.hasNext(); ) {
Integer element = i.next();
//To do
}
So if you doing any operation here, and the same time you modifying the collection, iterator under the hood got confuse and throws exception.
From JLS
List<? extends Integer> l = ...
for (float i : l) ...
will be translated to:
for (Iterator<Integer> #i = l.iterator(); #i.hasNext(); ) {
float #i0 = (Integer)#i.next();
...
ConcurrentModificationException in foreach loop even though I don't remove anything from arraylist
records.add(record);
You modified the ArrayList this line.
You can turn your for-each loop to indexed-for loop to prevent ConcurrentModificationException
, or maybe you can just create a new ArrayList
to hold your records:
ArrayList<Record> records = helper.get();
ArrayList<Record> result = new ArrayList<Record>();
for (Record x : records) {
Record record = new Record(many parameters);
result.add(record);
}
Related Topics
Compile-Time Constants and Variables
Where Do Java and .Net String Literals Reside
Synchronizing on an Integer Value
Java Regular Expression to Extract Content Within Square Brackets
How to Configure Encoding in Maven
Configuring Spring Security 3.X to Have Multiple Entry Points
How to Check CPU and Memory Usage in Java
Javafx 2.1 Tableview Refresh Items
Has Been Compiled by a More Recent Version of the Java Runtime (Class File Version 57.0)
Why Is My Uri Not Hierarchical
Import Package.* VS Import Package.Specifictype
How to Read All of Inputstream in Server Socket Java
How to Sort an Arraylist Using Multiple Sorting Criteria
How Is Countdownlatch Used in Java Multithreading
How to Convert Float to Int with Java
Run Single Test from a Junit Class Using Command-Line
Using Hibernate's Scrollableresults to Slowly Read 90 Million Records