Java.util.ConcurrentModificationException Examples And Resolution

When you operate a java collection object use iterator, you may always meet java.util.ConcurrentModificationException error. It is because the java collection object has been changed while others still use the method iterator.next() to loop in it. Below is just an example code that can throw concurrent modification exceptions.

1. Java Concurrent Modification Exception Examples.

  1. When you execute the below java code, you may see ConcurrentModificationException like below.
    Current phone is Apple
    Current phone is Google
    Current phone is Microsoft
    Exception in thread "main" java.util.ConcurrentHodificationException
              at java.uti1.ArrayList$Itr.checkForComodification(Unknown Source)
              at java.uti1.ArrayList$Itr.next(Unknown Source)
              at com.dev2qa.java.basic.collection.TestConcurrentModificationException.testListCMException(TestConcurrentModificationException.java:46)
              at com.dev2qa.java.basic.collection.TestConcurrentModificationException.main(TestC0ncurrentModificationException.java:19)
    
  2. ConcurrentModificationException occurred after removing one object in the java List.
    public static void testListCMException()
    {
    	/* Initiate a ArrayList object. */
    	List<String> phoneList = new ArrayList<String>();
    		
    	phoneList.add("Apple");
    	phoneList.add("Google");
    	phoneList.add("Microsoft");
    	phoneList.add("Huawei");
    	phoneList.add("Xiao Mi");
    	phoneList.add("Vivo");
    
    	/* Get the object's iterator. */
    	Iterator<String> it = phoneList.iterator();
    	
    	/* Iterate the object. */
    	while(it.hasNext())
    	{
    		String phone = it.next();
    		
    		System.out.println("Current phone is " + phone);
    		
    		/* Remove the object.*/
    		if(phone.equalsIgnoreCase("microsoft"))
    		{
    			/* ArrayList changed after remove, so it.next() will throw ConcurrentModificationException. */
    			phoneList.remove(phone);
    		}
    	}
    }
  3. ConcurrentModificationException occurred after add another key-value pair in java Map.
    public static void testMapCMException()
    {
    	/* Initiate a Map object. */
    	Map<String, String> osMap = new HashMap<String, String>();
    		
    	osMap.put("android", "android");
    	osMap.put("ios", "ios");
    	osMap.put("macos", "macos");
    	osMap.put("windows", "windows");
    	osMap.put("linux", "linux");
    	osMap.put("unix", "unix");
    
    
    	/* Get the map object's values collection. */
    	Collection<String> vCollection = osMap.values();
    	
    	/* Get vCollection' iterator. */
    	Iterator<String> it = osMap.values().iterator();
    		
    	/* Iterate vCollection. */
    	while(it.hasNext())
    	{
    		String os = it.next();
    		
    		System.out.println("OS is " + os);
    		
    		/* Add new object in the map.*/
    		if(os.equalsIgnoreCase("ios"))
    		{
    			/* After add, collection changed, so it.next() will throw ConcurrentModificationException. */
    			osMap.put("redhat", "redhat");
    		}
    	}
    }
  4. ConcurrentModificationException occurred with subList after original List change.
    public void testSubListCMException()
    {
    	List<String> fruitList = new ArrayList<>();
    	
    	fruitList.add("Apple"); 
    	fruitList.add("Orange");
    	fruitList.add("Banana"); 
    	fruitList.add("Pear"); 
    	fruitList.add("hawthorn"); 
    	
    	
    	List<String> subFruitList = fruitList.subList(0, 2);
    	
    	System.out.println(fruitList + " , " + subFruitList);
    	
    	fruitList.set(1, "Watermelon ");
    	
    	System.out.println(fruitList + " , " + subFruitList);
    	
    	// Add another fruit.
    	fruitList.add("cherry");
    	
    	/* Remove comment below code, get the sub list again after original list change 
    	can avoid ConcurrentModificationException. */
    	//subFruitList = fruitList.subList(0, 2);
    	
    	//Below code will throw ConcurrentModificationException, because original list fruitList changed.
    	System.out.println(fruitList +" , "+subFruitList);
    }

2. How To Fix Java ConcurrentModificationException.

  1. Jdk1.5 or higher provides Concurrent Collection classes that you can use to avoid this exception. CopyOnWriteArrayList and ConcurrentHashMap are two example class.
  2. CopyOnWriteArrayList Example.
    public static void testListWithoutCMException()
    {
    	/* Initiate a CopyOnWriteArrayList object. */
    	List<String> languageList = new CopyOnWriteArrayList<String>();
    	
    	languageList.add("java");
    	languageList.add("c++");
    	languageList.add("python");
    	languageList.add("perl");
    	languageList.add("javascript");
    	languageList.add("go");
    	
    	System.out.println("Strings before remove. ");
    	/* Print each string in the list before remove.*/
    	for(String codingLanguage : languageList)
    	{
    		System.out.println(codingLanguage);
    	}
    	
    	/* Get the object's iterator. */
    	Iterator<String> it = languageList.iterator();
    	
    	/* Iterate the object. */
    	while(it.hasNext())
    	{
    		String codingLanguage = it.next();
    		
    		/* Remove the object.*/
    		if(codingLanguage.equalsIgnoreCase("perl"))
    		{
    			languageList.remove(codingLanguage);
    			languageList.add("scala");
    		}
    	}
    	
    	System.out.println("");
    	System.out.println("Strings after remove. ");
    	/* Print each string in the list after remove.*/
    	for(String codingLanguage : languageList)
    	{
    		System.out.println(codingLanguage);
    	}
    }

    Below is the output of the above source code.

    List strings before remove
    java
    C++
    python
    perl
    javascript
    go
    List strings after remove.
    java
    C++
    python
    javascript
    go
    scala
  3. ConcurrentHashMap Example.
    public static void testMapWithoutCMException()
    {
    	/* Initiate a ConcurrentHashMap object. */
    	Map<String, String> dbMap = new ConcurrentHashMap<String, String>();
    	
    	dbMap.put("oracle", "oracle");
    	dbMap.put("mysql", "mysql");
    	dbMap.put("db2", "db2");
    	dbMap.put("sql server", "sql server");
    	dbMap.put("hadoop", "hadoop");
    	dbMap.put("mongodb", "mongodb");
    
    	/* Get the map object's values collection. */
    	Collection<String> vCollection = dbMap.values();
    	
    	/* Get vCollection' iterator. */
    	Iterator<String> it = dbMap.values().iterator();
    	
    	/* Iterate vCollection. */
    	while(it.hasNext())
    	{
    		String db = it.next();
    		
    		/* Add new object in the map.*/
    		if(db.equalsIgnoreCase("db2"))
    		{
    			dbMap.put("Big Table", "Big Table");
    		}
    	}
    	
    	
    	System.out.println("Map data after add. ");
    	
    	Set<String> dbKeySet = dbMap.keySet();
    	
    	Iterator<String> dbKeySetIt = dbKeySet.iterator();
    	
    	while(dbKeySetIt.hasNext())
    	{
    		String db = dbKeySetIt.next();
    		System.out.println("Database is " + db);
    	}
    }

    Output

    Map data after add.
    Database is oracle
    Database is Big Table
    Database is db2
    Database is mysql
    Database is hadoop
    Database is mongodb
    Database is sql server
    
  4. To fix the original List changed caused subList ConcurrentModificationException, you just need to get the subList again as below example source code.
    public void testSubListCMException()
    {
        List<String> fruitList = new ArrayList<>();
        
        fruitList.add("Apple"); 
        fruitList.add("Orange");
        fruitList.add("Banana"); 
        fruitList.add("Pear"); 
        fruitList.add("hawthorn"); 
        
        
        List<String> subFruitList = fruitList.subList(0, 2);
        
        System.out.println(fruitList + " , " + subFruitList);
        
        fruitList.set(1, "Watermelon ");
        
        System.out.println(fruitList + " , " + subFruitList);
        
        // Add another fruit in the list.
        fruitList.add("cherry");
        
        /* get the sub list again after original list change can avoid ConcurrentModificationException. */
        subFruitList = fruitList.subList(0, 2);
        
        //Below code will throw ConcurrentModificationException, because original list fruitList changed.
        System.out.println(fruitList +" , "+subFruitList);
    }
    
  5. Use for loop instead of the iterator.
    public void testListWithoutCMExceptionUseForLoop()
    {
    	/* Initiate a Arraylist object. */
    	List<String> ballList = new ArrayList<String>();
    	
    	ballList.add("football");
    	ballList.add("basketball");
    	ballList.add("volleyball");
    	
    	System.out.println("List strings before remove. ");
    	/* Print each string in the list before remove.*/
    	for(String ball : ballList)
    	{
    		System.out.println(ball);
    	}
    	
    	
    	int size = ballList.size();
    	for(int i = 0;i<size;i++)
    	{
    		String ball = ballList.get(i);
    		if("football".equalsIgnoreCase(ball))
    		{
    			ballList.add("table tennis");
    			
    			// After add, should recalculate the size.
    			size = ballList.size();
    		}
    		
    		if("basketball".equalsIgnoreCase(ball))
    		{
    			ballList.remove(ball);
    			
    			// After remove, should recalculate the size and i--.
    			i--;
    			size = ballList.size();
    		}
    	}
    	
    	
    	System.out.println("");
    	System.out.println("Strings after remove. ");
    	/* Print each string in the list after remove.*/
    	for(String ball : ballList)
    	{
    		System.out.println(ball);
    	}
    }

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.