Search code examples
javaforeachconcurrentmodification

ConcurrentModificationException: .add() vs .addAll()


Why does the following occur? Shouldn't both work?

List<String> items = data;
for( String id : items ) {
    List<String> otherItems = otherData;        

    // 1.   addAll()
    //Causes ConcurrentModificationException
    items.addAll(otherItems);

    // 2.   .add()
    //Doesn't cause exceptions
    for( String otherId : otherItems ) {
        items.add(otherId);
    }
}

Is it because add() adds to the collection Items, but addAll() creates a new collection thus modifying Items to be a different instance of List?

Edit items and otherItems are of concrete type ArrayList<String>.


Solution

  • Neither operation is proper, since it modifies the collection while iterating it.

    Examining the implementation of ArrayList shows that calling either add or addAll should successfully throw the ConcurrentModificationException on the next loop iteration. The fact that it isn't doing that for add means that either there is an obscure bug in the ArrayList class for the particular version of Java you have; or (more likely) otherItems is empty, so in the second case, you aren't actually calling add at all.

    I'm sure otherItems must be empty, because if adding to the Items list "worked" in the way you want, then it would grow every time around the loop, causing it to loop indefinitely until dying with an OutOfMemoryError.