Skip to content

Fail-fast vs fail-safe iterators

tldr

Fail-fast iterators (ArrayList, HashMap) throws ConcurrentModificationException if a collection is modified while iterating over it whereas fail-safe iterators (ConcurrentHashMap, CopyOnWriteArrayList) does not as they use copy of original collection.

Fail-fast

Fail-fast system shuts down its operation as-fast-as-possible when errors or failures occurs exposing those failures and errors immediately.

Fail-fast iterators does not tolerate any structural modifications (add, remove or update) to a collection while iterating over it. This is because collections maintain an internal counter called modCount. When an item is added or removed from the Collection, modCount counter gets incremented. When iterating, on each next() call, the current value of modCount gets compared with the initial value. If there’s a mismatch, it throws ConcurrentModificationException which shuts down the entire operation.

Default iterators for Collections from java.util package such as ArrayList, HashMap, etc. are Fail-Fast.

Removing element using Iterator‘s remove() method is entirely safe and no exception is throws whereas if Collection’s remove() is used, an exception is thrown.

public class Main {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
Integer integer = (Integer) it.next();
if (iterator.next() == 2) {
iterator.remove(); // this is safe
}
if (iterator.next() == 3) {
numbers.remove(2); // throws ConcurrentModificationException
}
list.add(4); // throws ConcurrentModificationException
}
}
}

Fail-safe

Fail-safe iterators on the other hand doesn’t throw any exception if the collection is modified while iterating over it. This is because fail-safe iterators work on the clone of the collection, so any structural modification done on the original collection goes unnoticed.

However, this convenience does come with some drawbacks. Firstly, iterator isn’t guaranteed to return updated data from the Collection as it’s working on the clone. Secondly, there’s an overhead of creating a copy of the Collection.

Iterators from java.util.concurrent package such as ConcurrentHashMap, CopyOnWriteArrayList, etc. are fail-safe.

public class Main {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();
map.put("key1", 1);
map.put("key2", 2);
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
map.put("key3", 3);// not be reflected in the Iterator
}
}
}