Search code examples
javafor-loopiteratorcopyonwritearraylist

Why CopyOnWriteArrayList's iterator allows remove() in enhanced-for loop, while its iterator does not support remove() operation?


CopyOnWriteArrayList

The iterator does NOT support the remove method.

But why does it work in enhanced-for loop?

List<String> lst = new CopyOnWriteArrayList<>();
lst.add("one"); 
lst.add("two"); 
lst.add("three"); 


for (String str : lst) { 
    if (str.equals("one")) { 
        lst.remove("two");   // no ConcurrentModificationException      
    } 
}        

System.out.println(lst);   // [one, three] => removed "two" !

List<String> lst = new ArrayList<>(); would generate ConcurrentModificationException

Javadoc clearly states that CopyOnWriteArrayList.iterator() does not support remove() => it shall throw UnsupportedOperationException! I understand it is weakly consistent - say there is no ConcurrentModificationException if I add elements to CopyOnWriteArrayList after I obtained an iterator from that CopyOnWriteArrayList

P.S. Sorry, I was inattentive - I called remove() not on the iterator! I was confused by being inside enhanced-for (it uses an iterator implicitly).


Solution

  • CopyOnWriteArrayList iterator fail safe implementation supports modify actions.

    When you iterate over a CopyOnWriteArrayList and CopyOnWriteArraySet the iterator uses a snapshot of the underlying list (or set) and does not reflect any changes to the list or set after the snapshot was created. The iterator will never throw a ConcurrentModificationException.

    Read more at: https://markusjais.com/java-concurrency-understanding-copyonwritearraylist-and-copyonwritearrayset/

    By the way, in classic List implementation like ArrayList() etc, you don't need to use iterator explicitly. Use list.removeIf(predicate) method.