How to avoid ConcurrentModificationException while removing elements from `ArrayList` while iterating it?
Use an Iterator
and call remove()
:
Iterator<String> iter = myArrayList.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}
java.util.ConcurrentModificationException thrown when adding to List
The ConcurrentModificationException
is thrown when calling String value = it.next();
. But the actual culprit is list.add("6");
. You mustn't modify a Collection
while iterating over it directly. You are using it.remove();
which is fine, but not list.add("6");
.
While you can solve the problem with Stream
s, I will first offer a solution with Iterator
s, as this is a good first step for understanding the problem.
You need a ListIterator<String>
if you want to add and remove during iteration:
for (ListIterator<String> it = list.listIterator(); it.hasNext();){
String value = it.next();
if (value.equals("4")) {
it.remove();
it.add("6");
}
System.out.println("List Value: " + value);
}
This should do the trick!
A solution using Stream
s:
List<String> newList = list.stream()
.map(s -> s.equals("4") ? "6" : s)
.collect(Collectors.toList());
Here we create a Stream
from your List
. We map
all values to themselves, only "4"
gets mapped to "6"
and then we collect it back into a List
. But caution, newList
is immutable!
ConcurrentModificationException for ArrayList
You can't remove from list if you're browsing it with "for each" loop. You can use Iterator
. Replace:
for (DrugStrength aDrugStrength : aDrugStrengthList) {
if (!aDrugStrength.isValidDrugDescription()) {
aDrugStrengthList.remove(aDrugStrength);
}
}
With:
for (Iterator<DrugStrength> it = aDrugStrengthList.iterator(); it.hasNext(); ) {
DrugStrength aDrugStrength = it.next();
if (!aDrugStrength.isValidDrugDescription()) {
it.remove();
}
}
Concurrent Modification Exception in Callable class
public MyCallable (List<Instance> instances) {
this.instances = Collections.synchronizedList(instances);
}
Using synchronizedList
like this doesn't help you in the way you think it might.
It's only useful to wrap a list in a synchronizedList
at the time you create it (e.g. Collections.synchronizedList(new ArrayList<>())
. Otherwise, the underlying list is directly accessible, and thus accessible in an unsynchronized way.
Additionally, synchronizedList
only synchronizes for the duration of individual method calls, not for the whole time while you are iterating over it.
The easiest fix here is to take a copy of the list in the constructor:
this.instances = new ArrayList<>(instances);
Then, nobody else has access to that list, so they can't change it while you are iterating it.
This is different to taking a copy of the list in the call
method, because the copy is done in a single-threaded part of the code: no other thread can be modifying it while you are taking that copy, so you won't get the ConcurrentModificationException
(you can get a CME in single-threaded code, but not using this copy constructor). Doing the copy in the call
method means the list is iterated, in exactly the same way as with the for
loop you already have.
ConcurrentModificationException when using stream with Maps key set
@Eran already explained how to solve this problem better. I will explain why ConcurrentModificationException
occurs.
The ConcurrentModificationException
occurs because you are modifying the stream source. Your Map
is likely to be HashMap
or TreeMap
or other non-concurrent map. Let's assume it's a HashMap
. Every stream is backed by Spliterator
. If spliterator has no IMMUTABLE
and CONCURRENT
characteristics, then, as documentation says:
After binding a Spliterator should, on a best-effort basis, throw
ConcurrentModificationException
if structural interference is detected. Spliterators that do this are called fail-fast.
So the HashMap.keySet().spliterator()
is not IMMUTABLE
(because this Set
can be modified) and not CONCURRENT
(concurrent updates are unsafe for HashMap
). So it just detects the concurrent changes and throws a ConcurrentModificationException
as spliterator documentation prescribes.
Also it worth citing the HashMap
documentation:
The iterators returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a
ConcurrentModificationException
. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw
ConcurrentModificationException
on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
While it says about iterators only, I believe it's the same for spliterators.
Why im not getting concurrent modification exception during update of collection element?
why updating should cause concurrent modification?
If by "updating" you mean calling the set
method, it won't cause concurrent modification.
Setting the value of an element in the List
is not a structural modification, and therefore doesn't cause ConcurrentModificationException
when performed during iteration.
Quotes from the ArrayList
Javadoc:
A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification
...The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
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.
ConcurrentModificationException in LinkedList
The ConcurrentModificationException
is usually thrown when iterating through the list and in the same time usually another thread or even the same loop tries to modify (add / remove) the contents of the list.
Related Topics
Java.Lang.Classnotfoundexception: Com.Mysql.Jdbc.Driver in Eclipse
How to Import a Class from Default Package
How to Iterate Through the Files in a Directory and It's Sub-Directories in Java
Generate/Get Xpath from Xml Node Java
What Is the Garbage Collector in Java
What Is an Outofmemoryerror and How to Debug and Fix It
How to Set the Classpath in Netbeans
How to Create a Rest Client for Java
What Is @Modelattribute in Spring MVC
Which Is the Best Library for Xml Parsing in Java
Java Class That Implements Map and Keeps Insertion Order
Reading a List from Properties File and Load with Spring Annotation @Value
Most Simple Code to Populate Jtable from Resultset
How to Override Class Variables in Java
Closing Database Connections in Java
Using Prepared Statements to Set Table Name
Jrbeancollectiondatasource: How to Show Data from the Java.Util.List from Javabean