Saturday 4 May 2013

Why and when can we encounter ConcurrentModificationException in Java.

Background

If you are a  beginner level Java developer and experimenting with Collections you may encounter this exception. Even I was taken with surprise when i first encountered such Exception.Let see why and when do we get such an Exception.
    Before we proceed take a look at the Iterator Example code in the post on Understanding Iterators. We will refer to a lot of things from that post.

Now if you recall the Iterator interface it was like -

public interface Iterator<E>

{
    boolean hasNext();
    E next();
    void remove();
}


Iterator object has a remove function but generally beginners tend to forget that. See the following code when you will encounter  ConcurrentModificationException.


Example Code

package testCodes;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class IteratorDemo {

    public static void main(String[] args) {

        List<String> nameList = new ArrayList<String>();
        nameList.add("John");
        nameList.add("Sam");
        nameList.add("kenny");

        nameList.add("Jessica");

        Iterator<String> namesIterator = nameList.iterator();
        System.out.println("Printing names");
        while (namesIterator.hasNext()) {
            String name = namesIterator.next();
            if (name.equals("Sam")) {
                nameList.remove(name);
            }
            System.out.println(name);
        }
    }
}

 Output


 Explanation

    Why did we get this Exception. Reason is simple. When we Iterate using an Iterator, Iterator objects expects there should be no modification in the  Collections which it points to. So how do we remove one might ask. For this reason we have .remove() method in Iterator interface. You can do something like below - 

while (namesIterator.hasNext()) {
            String name = namesIterator.next();
            if (name.equals("Sam")) {
                namesIterator.remove();
            }
            System.out.println(name);
     }


Code will correctly compile and run. It's a very simple point but programmers tend to forget it some time.

So basically you should not modify the collection when it is being iterated upon. Another simple example that would throw this exception is

        Map<String, Object> myMap = new HashMap<String, Object>();
        myMap.put("Aniket", 1);
        myMap.put("Abhijit", 2);
        for(String key: myMap.keySet()) {
            myMap.remove(key);
        }


Solution as I mentioned above is to use remove() method of the iterator.Another option could be use concurrent collections. See following example -

        Map<String, Object> myMap = new ConcurrentHashMap<String, Object>();
        myMap.put("Aniket", 1);
        myMap.put("Abhijit", 2);
        for(String key: myMap.keySet()) {
            myMap.remove(key);
        }


What internally happens is as soon as data is updated in a collection the corresponding iterator is updated too which generally does not happen in normal collections.


Related Links


No comments:

Post a Comment

t> UA-39527780-1 back to top