Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.util.ConcurrentModificationException not thrown when expected

Tags:

java

exception

The following code throws a java.util.ConcurrentModificationException, as expected:

   public void test(){
      ArrayList<String> myList = new ArrayList<String>();

      myList.add("String 1");
      myList.add("String 2");
      myList.add("String 3");
      myList.add("String 4");
      myList.add("String 5");

      for(String s : myList){
         if (s.equals("String 2")){
            myList.remove(s);
         }
      }
   }

However, the following code does not throw the Exception, while I expect it to be thrown:

   public void test(){
      ArrayList<String> myList = new ArrayList<String>();

      myList.add("String 1");
      myList.add("String 2");
      myList.add("String 3");

      for(String s : myList){
         if (s.equals("String 2")){
            myList.remove(s);
         }
      }
   }

The difference is that the first list contains 5 items, while the second list contains 3. The JVM used is:

java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode)

The question: why does the second piece of code NOT throw the java.util.ConcurrentModificationException?

like image 267
Gijs Overvliet Avatar asked Jul 27 '14 11:07

Gijs Overvliet


People also ask

How do I fix Java Util ConcurrentModificationException?

How do you fix Java's ConcurrentModificationException? There are two basic approaches: Do not make any changes to a collection while an Iterator loops through it. If you can't stop the underlying collection from being modified during iteration, create a clone of the target data structure and iterate through the clone.

What is Java Util ConcurrentModificationException?

The java. util. concurrentmodificationexception is an error in Java. The error occurs when the iterator is traversing a list, and a command is used to change an element's value during that traversal.


2 Answers

The iterator returned from ArrayList.iterator() in the implementation we're apparently both using only checks for structural modification in calls to next(), not in calls to hasNext(). The latter just looks like this (under Java 8):

public boolean hasNext() {
    return cursor != size;
}

So in your second case, the iterator "knows" that it's returned two elements, and that the list only has two elements... so hasNext() just returns false, and we never end up calling next() the third time.

I would view this as an implementation detail - basically the checking not being as strict as it could be. It would be entirely reasonable for hasNext() to perform a check and throw an exception in this case too.

like image 165
Jon Skeet Avatar answered Oct 23 '22 17:10

Jon Skeet


Note also the last paragraph of the ArrayList documentation summary:

Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.

If you're worrying about forcing lists to be read-only, use the Collections.unmodifiableList method, instead of checking for ConcurrentModificationException, which as mentioned above is not guaranteed to be thrown in all relevant cases.

like image 32
Peter O. Avatar answered Oct 23 '22 17:10

Peter O.