fail-fast vs fail-safe Iterators in Java

1. Introduction

In Java, iterators are used to traverse collections. There are two types of iterators in terms of their behavior when the underlying collection is modified while iteration is in progress: fail-fast and fail-safe. 

Fail-fast iterators immediately throw a ConcurrentModificationException if they detect that the collection has been modified during iteration. Fail-safe iterators, on the other hand, do not throw any exception because they operate on a copy of the collection.

2. Key Points

1. Fail-fast iterators throw ConcurrentModificationException on detecting modifications made to a collection during iteration.

2. Fail-safe iterators allow modifications to a collection while iterating because they work on a clone of the collection.

3. Fail-fast iterators are typically provided by collections in the java.util package, such as ArrayList and HashMap.

4. Fail-safe iterators are often used in concurrent collections from the java.util.concurrent package, like CopyOnWriteArrayList.

3. Differences

Fail-Fast Fail-Safe
Detects concurrent modification. Does not detect concurrent modification.
Throws ConcurrentModificationException. Do not throw exceptions on modification.
Works directly on the original collection. Works on a clone of the original collection.

4. Example


// Example of Fail-Fast Iterator
import java.util.ArrayList;
import java.util.Iterator;

public class FailFastExample {
    public static void main(String[] args) {
        ArrayList<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);

        Iterator<Integer> iterator = numbers.iterator();

        while (iterator.hasNext()) {
            Integer number = iterator.next();
            System.out.println(number);
            if (number.equals(2)) {
                // Modifying ArrayList after creating Iterator should throw ConcurrentModificationException
                numbers.remove(number);
            }
        }
    }
}

// Example of Fail-Safe Iterator
import java.util.concurrent.CopyOnWriteArrayList;

public class FailSafeExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<Integer> numbers = new CopyOnWriteArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);

        Iterator<Integer> iterator = numbers.iterator();

        while (iterator.hasNext()) {
            Integer number = iterator.next();
            System.out.println(number);
            if (number.equals(2)) {
                // Modifying CopyOnWriteArrayList after creating Iterator doesn't throw any exception
                numbers.remove(number);
            }
        }
    }
}

Output:

// Output from FailFastExample:
1
2
Exception in thread "main" java.util.ConcurrentModificationException
// Output from FailSafeExample:
1
2
3

Explanation:

1. In the FailFastExample, the ArrayList is modified after the iterator is created, which triggers a ConcurrentModificationException.

2. In the FailSafeExample, the CopyOnWriteArrayList is modified during iteration, but since the iterator works on a separate copy, no exception is thrown and iteration continues for all elements.

5. When to use?

- Use fail-fast iterators when you want to prevent concurrent modification and ensure the collection remains unchanged during iteration.

- Use fail-safe iterators when you need to allow modifications to the collection while iterating, such as in a multithreaded environment where you don't want an iterator's behavior to be affected by other threads' actions.

Comments