In Java, concurrentmodificationexception is one of the common problems that programmer faces while programmer works on Collections in java. In this post, we will see why we encountered this exception and how to resolve concurrent modification exception in java.
Here is the table content of the article we will cover these topics.
- What is concurrentmodificationexception in java?
- Why concurrent modification exception occurs in java? OR Reason behind the scenes?
- How to resolve concurrentmodificationexception in java OR avoid concurrentmodificationexception in java?
- Avoid ConcurrentModificationException in a single-threaded environment
1. By of Iterator.remove() method
2. By use of foreach but not Removing During Iteration
3. Use traditional for loop
4. Using removeIf() method of Java 8 - Avoid ConcurrentModificationException in a multi-threaded environment
What is concurrentmodificationexception in java
The concurrentmodificationexception occurs when we try to modify any object concurrently without permission. You may be faced with it when you work with Collection classes of Java. When you try to modify any collection class during the traversal the compiler throw ConcurrentModificationException. You will see the Exception in the main thread “java util concurrent modification exception”. This exception can occur in a multithread environment as well as in a single thread environment.
The Collection classes in java are fail-fast, which means we can’t modify the collection when a thread is traversing over it using an iterator, the iterator.next()
will throw ConcurrentModificationException. Don’t get confused when we are talking about threads, because it can create confusion in the developer’s mind that the collection is getting modified by multiple threads and that is not true. It can also occur with multiple threads.
Suppose we have an ArrayList, and we are traversing it and trying to remove any element. If we use enhance for loop and try to remove an element by the remove() method, then it will give the ConcurrentModificationException but if we use Iterator’s remove method, then we will be able to remove the element successfully. We will discuss it separately.
But there are some collections that are fail-safe like CopyOnWriteArrayList, which creates a new copy ArrayList during modification. Let’s take a concurrentmodificationexception example.
import java.util.ArrayList; import java.util.List; public class Record { public static void main(String arg[]) { List<String> listOfBooks = new ArrayList<>(); listOfBooks.add("Programming in Java"); listOfBooks.add("Clean Code"); listOfBooks.add("Improve Java"); listOfBooks.add("Complete learning"); // Traversing the list by enhanced for loop for(String book: listOfBooks) { System.out.println(book); // Removing the object if condition is true if(book.contains("Clean Code")) { listOfBooks.remove(book); } } } }
Output: Programming in Java
Clean Code
Exception in thread “main” java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996)
at Record.main(Record.java:15)
In the above example you can see the exception even if we are not working in multithreading we just have one thread, that is the main thread. The enhanced for loop internally uses the iterator. The compiler is throwing an error because we are using the remove method of collection instead of the iterator. See the reason here.
.Hence, Let’s take a different example and different methods of the transversal. We will see the working of each traversal method and find in which method it creates the problem.
Let’s take an example of ArrayList and transverse the ArrayList by use of for loop.
import java.util.ArrayList; import java.util.List; public class Record { public static void main(String arg[]) { List<String> listOfNames = new ArrayList<String>(); listOfNames.add("Hi"); listOfNames.add("Java"); listOfNames.add("Goal"); listOfNames.add(".com"); listOfNames.add("Website"); // Traversing the names from ArrayList for(int i = 0; i < listOfNames.size(); i++) { System.out.println(listOfNames.get(i)); // Modifying the ArrayList if condition is true if(listOfNames.get(i).equals("Hi")) listOfNames.remove(listOfNames.get(i)); } } }
Output: Hi
Goal
.com
Website
This might be a surprising thing for you because it has run successfully, and it does not throw an exception because here we are not using iterator. The ConcurrentModificationException directly belongs to the Iterator not to remove the method of ArrayList. We will see the reason below section.
Let’s take the example of ArrayList and transverse the ArrayList by use of Iterator.
import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Record { public static void main(String arg[]) { List<String> listOfBooks = new ArrayList<>(); listOfBooks.add("Programming in Java"); listOfBooks.add("Clean Code"); listOfBooks.add("Improve Java"); listOfBooks.add("Complete learning"); // Traversing the list by Iterator Iterator<String> it = listOfBooks.iterator(); while(it.hasNext()) { String book = it.next(); System.out.println(book); // Removing the object if condition is true if(book.contains("Clean Code")) { listOfBooks.remove(book); } } } }
Output: Programming in Java
Clean Code
Exception in thread “main” java.util.ConcurrentModificationException at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042) at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996) at Record.main(Record.java:19)
This is also showing the exception because we are using an iterator and trying to modify the collection by removing the method of collection.
Why concurrent modification exception occurs in java? OR Reason behind the scenes?
The ConcurrentModificationException occurs when we iterate the collection class by Iterator and modify the collection during the iteration. The ConcurrentModificationException belongs to the Iterator, not to the Collection classes.
Now let’s see why Iterator gives an exception. Take the simple example of the ArrayList class. The ArrayList class internally implements the Iterator interface. Let’s have a look at the code, here you can see it:
- There is a nested class that implemented the Iterator interface and here modCount variable is assigned to expectedModCount. The modCount is a variable that tells the number of times this ArrayList has been structurally modified. Structural modifications means those modifications that can change the size of the list. Whenever we modify the ArrayList, like add or remove any object then its modCount gets updated automatically.
2. When the next() method of iterator invokes the checkForComodification() method that checks whether the ArrayList has modified during iteration or not.
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
If modCount doesn’t match with expectedModCount then it throws ConcurrentModificationException.
How to resolve concurrentmodificationexception in java OR avoid concurrentmodificationexception in java?
Let’s see how we can resolve ConcurrentModificationException or avoid ConcurrentModificationException. It can occur in a single thread or in multiple threads. Let’s discuss it one by one.
Avoid ConcurrentModificationException in a single-threaded environment
1. By of Iterator.remove() method
As we have discussed the reason for the exception is the next() method of Iterator. If you are not familiar with reading it first. So, we can use the remove() method of the Iterator to remove the object during the iteration. The remove() method of Iterator assigns the value of modCount to the expectModCount. That’s why the next() method doesn’t throw exceptions. Let’s have a look at the code of the remove method:
public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } }
import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Record { public static void main(String arg[]) { List<String> listOfBooks = new ArrayList<>(); listOfBooks.add("Programming in Java"); listOfBooks.add("Clean Code"); listOfBooks.add("Improve Java"); listOfBooks.add("Complete learning"); // Traversing the list by Iterator for loop Iterator<String> it = listOfBooks.iterator(); while(it.hasNext()) { String book = it.next(); System.out.println(book); // Removing the current object if condition is true if(book.contains("Clean Code")) { it.remove(); } } System.out.println("After remove: "+ listOfBooks); } }
Output: Programming in Java
Clean Code
Improve Java
Complete learning
After remove: [Programming in Java, Improve Java, Complete learning]
But there are two problems to use the Iterator: the first problem, you can remove the same object and not any other object from the list. Second problem, if we use Nested Iterator that creates confusion for the programmer. So, there may be a chance when we want to use the enhanced for loop. We will discuss it below.
2. By use of foreach but not Removing During Iteration
Suppose you are working on the existing project and you don’t want to change the existing code. So, you can keep it as it is, but you can perform a remove operation after the completion of an iteration.
import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Record { public static void main(String arg[]) { List<String> listOfBooks = new ArrayList<>(); listOfBooks.add("Programming in Java"); listOfBooks.add("Clean Code"); listOfBooks.add("Improve Java"); listOfBooks.add("Complete learning"); List<String> toRemove = new ArrayList<String>(); for (String book : listOfBooks) { System.out.println(book); if(book.equals("Clean Code")) toRemove.add(book); } listOfBooks.removeAll(toRemove); System.out.println(listOfBooks); } }
Output: Programming in Java
Clean Code
Improve Java
Complete learning
[Programming in Java, Improve Java, Complete learning]
3. Use traditional for loop
You can simply use the traditional for to avoid it. Because this exception belongs to Iterator and traditional for loop doesn’t use the Iterator, unlike a for-each loop.
import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Record { public static void main(String arg[]) { List<String> listOfBooks = new ArrayList<>(); listOfBooks.add("Programming in Java"); listOfBooks.add("Clean Code"); listOfBooks.add("Improve Java"); listOfBooks.add("Complete learning"); for (int i = 0; i < listOfBooks.size(); i++) { String book = listOfBooks.get(i); System.out.println(book); if(book.equals("Clean Code")) listOfBooks.remove(i); } System.out.println(listOfBooks); } }
Output: Programming in Java
Clean Code
Improve Java
Complete learning
[Programming in Java, Improve Java, Complete learning]
4. Using removeIf() method of Java 8
Let’s see how we can remove concurrentmodificationexception java 8 introduced a new method in the Collection interface that removes the element if a given condition is true. It takes the parameter of Predicate type, if you are not familiar with functional programming, then read it from here.
import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Record { public static void main(String arg[]) { List<String> listOfBooks = new ArrayList<>(); listOfBooks.add("Programming in Java"); listOfBooks.add("Clean Code"); listOfBooks.add("Improve Java"); listOfBooks.add("Complete learning"); System.out.println("Before :" + listOfBooks); listOfBooks.removeIf(name -> name.equals("Clean Code")); System.out.println("After :" +listOfBooks); } }
Output: Before :[Programming in Java, Clean Code, Improve Java, Complete learning]
After :[Programming in Java, Improve Java, Complete learning]
Avoid ConcurrentModificationException in a multi-threaded environment
- We can convert the ArrayList to Array and then perform the operation but this is not a good suit for many cases. It is good when we have a small-size list because if the list size is big then it creates performance issues.
- By the use of synchronization in java, we can achieve this task. We can use the lock concept. In this approach, one thread will wait when another is having the lock. But it prevents multithreading concepts.
- You can also use the concurrent collections of java.