How to avoid ConcurrentModificationException for map or List
The ConcurrentModificationException
exception is thrown due to one thread trying to read the object and the other thread trying to modify the object.
This happens to all java collection API classes - List
, HashMap
, HashTable
, LinkedHashMap
In the below example
- Create an ArrayList of Strings.
- Create an Iterator using Iterate using the
iterator()
method - Check for the next element exists or not using the hasNext() method
- if the next element exists, Print the element
- During iteration, Trying to remove an element based on a Conditional check
- This will throw an error
Exception in thread "main" java.util.ConcurrentModificationException
ArrayList throws java.util.ConcurrentModificationException while removing an item during iteration
Here are the examples
- Single thread is reading list using iterator and
- Removing an element during iteration causes this exception
java.util.Iterator
are fail-fast iteration that throws an error during iteration
and modifies
a collection.
import java.util.ArrayList;
import java.util.Iterator;
public class App {
public static void main( String[] args ){
ArrayList<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("four");
list.add("five");
Iterator<String> strIterator = list.iterator();
while (strIterator.hasNext()) {
String nextString = strIterator.next();
System.out.println("Current Object: " + nextString);
if (nextString.equals("five"))
list.remove(nextString);
}
}
}
Output
Current Object: one
Current Object: two
Current Object: three
Current Object: four
Current Object: five
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at App.main(App.java:15)
Process finished with exit code 1
This is not possible to remove an element from the array list with the list.remove()
method during iteration. list.remove() method is not safe to remove an element during iteration.
How to iterate list avoiding ConcurrentModificationException while removing objects
It is a solution or fix for ConcurrentModificationException for the java list.
You can use the remove()
method from java.util.Iterator
instead of list.remove()
Iterator.remove is a safe method to change collection during iteration.
import java.util.ArrayList;
import java.util.Iterator;
public class App {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
Iterator<String> strIterator = list.iterator();
while (strIterator.hasNext()) {
String nextString = strIterator.next();
System.out.println("Current Object: " + nextString);
if (nextString.equals("five"))
strIterator.remove();
}
System.out.println(list);
}
}
HashMap concurrently modified exception
This happens for the below map and list of collections.
- Modifying the state of any key or value in map implementations(example,) during an iteration of Map objects
- Adding/removing (Iterator.remove) the object is a collections class while iteration of collection of objects at the same time.
- Below example does not throw this exception as changing the key and value and hashmap size is not changing, This is an example of modifying the collection while iteration of hashmap.
Iteration is done in three ways - iterator
, map.entrySet
with loop.
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class App {
public static void main(String[] args) {
HashMap<String, String> mapDemo = new HashMap<>();
mapDemo.put("key-1", "value-1");
mapDemo.put("key-2", "value-2");
mapDemo.put("key-3", "value-3");
Iterator<String> iterator = mapDemo.keySet().iterator();
while(iterator.hasNext()) {
String key = iterator.next();
System.out.println("Map Value:" + mapDemo.get(key));
if (key.equals("key-2")) {
mapDemo.put("key-2", "newvalue");
}
}
for (Map.Entry<String, String> entry : mapDemo.entrySet()) {
if (entry.getKey().contains("key-2")) {
entry.setValue("new Value-2");
}
}
for (Map.Entry entry : mapDemo.entrySet()) {
System.out.println(entry.getKey() + "===" + entry.getValue());
}
}
}
Output
Map Value:value-1
Map Value:value-3
Map Value:value-2
key-1===value-1
key-3===value-3
java8 to fix ConcurrentModificationException with removeIf method
java8 introduced the removeIf
method in collections classes.
import java.util.ArrayList;
public class App {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
System.out.println(list);
list.removeIf(item -> item == "five");
System.out.println(list);
}
}
[one, two, three, four, five]
[one, two, three, four]
How to avoid ConcurrentModificationException in java?
ConcurrentModificationException
thrown in single threaded
and multi threaded
applications.
- You can use
ConcurrentHashMap
,ConcurrentSkipListMap
,ConcurrentLinkedQueue
,CopyOnWriteArrayList
,CopyOnWriteArrayList
classes fromjava.util.concurrent
modules in java7 version onwards. - You can use Iterator. remove removing an object from the collection during iteration
- You can also use synchronized block by having a lock on collections, thus decreasing performance, but not safe to use it
- You can also use the
removeIf
method fromjava8
Conclusion
To Sump up, We have seen ConcurrentModifiedException for collections during modifying an object while doing iteration, and solutions are specified for List and Map, with java8.