Java — How to deal with ConcurrentModificationException in Java | Code Factory
Donate : Link
WordPress Blog : Link
Applications… : Link
One of the common problem while removing elements from an ArrayList in Java is the ConcurrentModificationException
.
If you use classical for loop with the index or enhanced for loop and try to remove an element from the ArrayList using remove() method, you will get the ConcurrentModificationException
but if you use Iterator's remove() method or ListIterator's remove() method, then you won't get this error and be able to remove the element.
It’s an unwritten rule in Java that while looping through the list, you should not add() or remove() elements until the collection supports fail-safe Iterator e.g. CopyOnWriteArrayList, which operate on a copy of list rather than the original list.
The main problem with this error is that it confuses developer that list is getting modified by multiple threads and that’s why Java is throwing this error, it’s not true. Most of the time ConcurrentModificationException comes even without multiple threads modifying the list.
Using for each loop and ArrayList.remove(index)
package com.example.java.programming;import java.util.ArrayList;
import java.util.List;/**
* @author code.factory
*
*/
public class ArrayListExample { public static void main(String... args) {
List<String> names = new ArrayList<>();
names.add("Narendra");
names.add("Amit");
names.add("Rahul");
names.add("Yogi"); System.out.println("List before : " + names);
/*
* Using forEach loop to iterate and removing element during iteration will
* throw ConcurrentModificationException in Java
*/
for (String name : names) {
if (name.contains("i")) {
names.remove(name);
}
}
System.out.println("List after : " + names);
}
}
Output :
List before : [Narendra, Amit, Rahul, Yogi]
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 com.example.java.programming.ArrayListExample.main(ArrayListExample.java:24)
You can see that this error comes even though we just have one thread, main thread which is operating with ArrayList. The ConcurrentModification error comes because we are not using Iterator, instead just calling listOfBooks.remove() method.
Using classical for loop and ArrayList.remove(index)
Here is another interesting code example of removing elements from ArrayList. Surprisingly this code will not throw ConcurrentModificationException when you first run it? do you know why?
Well, try it before you look at the explanation after the code. It’s really this kind of minor details about Java programming language and Collection framework, which will make you a good developer.
package com.example.java.programming;import java.util.ArrayList;
import java.util.List;/**
* @author code.factory
*
*/
public class ArrayListExample { public static void main(String... args) {
List<String> names = new ArrayList<>();
names.add("Narendra");
names.add("Amit");
names.add("Rahul");
names.add("Yogi"); System.out.println("List before : " + names);
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
if (name.contains("i")) {
System.out.println("Removing " + name);
names.remove(i); // will throw CME
}
}
System.out.println("List after : " + names);
}
}
Output :
List before : [Narendra, Amit, Rahul, Yogi]
Removing Amit
Removing Yogi
List after : [Narendra, Rahul]
This code doesn’t throw ConcurrentModificationException because here we are not using Iterator but we are just using traditional for loop.
It’s the Iterator which throws ConcurrentModificationException, and not the remove method of ArrayList, hence you don’t see that error in below code.
If you look at the code for ArrayList.java, you will notice that there is a nested class which implemented Iterator interface and it’s next() method calls checkForComodification() function which actually checks if ArrayList has modified during iteration or not, if modCount doesn’t match with expectedModCount then it throws ConcurrentModificationException.
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
Using Iterator but ArrayList’s remove method
package com.example.java.programming;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;/**
* @author code.factory
*
*/
public class ArrayListExample { public static void main(String... args) {
List<String> names = new ArrayList<>();
names.add("Narendra");
names.add("Amit");
names.add("Rahul");
names.add("Yogi"); System.out.println("List before : " + names);
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
names.remove(name);
}
System.out.println("List after : " + names);
}
}
Output :
List before : [Narendra, Amit, Rahul, Yogi]
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 com.example.java.programming.ArrayListExample.main(ArrayListExample.java:23)
The real problem with this code is that even though the code is using Iterator to go over ArrayList, it’s not really using the Iterator.remove() method to remove the element. It is just using Iterator to get the next element but calling the ArrayList.remove() method to delete the element.
Right way to remove element is by using Iterator’s remove method
Finally, here is the right way to delete an element from ArrayList during iteration. In this example, we have used Iterator both iterate as well as remove the element. The code is ok but it has a serious limitation, you can only use this code to remove the current element. You cannot remove any arbitrary element from ArrayList in Java.
package com.example.java.programming;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;/**
* @author code.factory
*
*/
public class ArrayListExample { public static void main(String... args) {
List<String> names = new ArrayList<>();
names.add("Narendra");
names.add("Amit");
names.add("Rahul");
names.add("Yogi"); System.out.println("List before : " + names);
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
System.out.println("Removing : " + name);
iterator.remove();
}
System.out.println("List after : " + names);
}
}
Output :
List before : [Narendra, Amit, Rahul, Yogi]
Removing : Narendra
Removing : Amit
Removing : Rahul
Removing : Yogi
List after : []
The same behavior is applicable to ListIterator as well. I mean you can replace Iterator with ListIterator and code will work fine. The ListIterator also allow you to navigate in both directions i.e. forward and backward.