Friday, August 5, 2016

Why for each loop doesn't throw ConcurrentModification exception in case List has only 2 elements


List<Person> first = new ArrayList<Person>();
        Person p1=new Person("p1", 1);
        Person p2=new Person("p2", 2);
        Person p3=new Person("p3", 3);
        
        first.add(p1);
        first.add(p2);
        first.add(p3);
        
        for(Person p: first)
        {
            first.remove(p);
        }

The above code will throw ConcurrentModificationException

Now remove the following code

first.add(p3);

And re-execute the code...

Now you'll see that no exception will be thrown...

What's the reason behind this?

Actually for-each loop uses Iterator behind the scenes

which gets converted to the following

        Iterator i = first.iterator();
        while(i.hasNext())
        {
            Person px = (Person)i.next();
            first.remove(px);
        } 

In case of two elements, here are the steps that are followed
  • Iterator is created
  • hasNext returns true
  • .next method returns the first element of the list
  • First element is removed. Now list contains only 1 element.
  • As iterator has already traversed one element and also list has 1 element, hasNext method will return false
  • Hence the loop terminates.
In case of three elements, here are the steps that are followed
  • Iterator is created
  • hasNext returns true
  • .next method returns the first element of the list
  • First element is removed. Now list contains 2 elements.
  • As iterator has already traversed one element and list has 2 elements, hasNext method will return true
  • control will enter the loop
  • .next method will see that iterator has been modified and hence throw a ConcurrentModificationException