Post

ConcurrentModificationException in Java and How to Prevent It



Introduction

ConcurrentModificationException is a runtime exception that occurs when a collection is structurally modified while iterating over it in a way that violates the expected behavior of the iterator. This often happens when a collection is modified directly (e.g., by adding, removing, or updating elements) while iterating through it using loops or iterators.

Causes of ConcurrentModificationException

The most common cause of this exception is modifying a collection during iteration without using a safe approach. For example, calling add(), remove(), or put() on a collection while an iterator is traversing through it. Java’s ArrayList, HashSet, and HashMap are examples of collections that can trigger this exception if modified during iteration.

Example: Failing Scenario

Here’s an example that demonstrates how ConcurrentModificationException can occur:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.ArrayList;
import java.util.List;

public class ConcurrentModificationExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");

        // Iterating over the list
        for (String item : list) {
            // Attempt to modify the list during iteration
            if ("B".equals(item)) {
                list.remove(item); // This will throw ConcurrentModificationException
            }
        }
    }
}

In this example, when trying to remove an element from the list during iteration, Java throws a ConcurrentModificationException because the collection was modified while it was being iterated.

Internal Working of Fail-Fast Mechanism

Java’s fail-fast iterators are designed to throw this exception to prevent unexpected behavior. When a collection is created, an internal counter (known as modCount) is initialized. Every structural modification to the collection increments this counter. When an iterator is created, it takes a snapshot of the modCount. During iteration, if it detects any changes to the modCount, it throws a ConcurrentModificationException.

This mechanism ensures that concurrent modification issues are caught early rather than resulting in inconsistent data during runtime.

Solutions to Avoid ConcurrentModificationException

There are several ways to avoid ConcurrentModificationException while modifying a collection during iteration:

1. Use Iterator.remove()

Instead of modifying the collection directly, use the remove() method provided by the iterator:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class SafeRemovalExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String item = iterator.next();
            if ("B".equals(item)) {
                iterator.remove(); // Safely removes element during iteration
            }
        }
    }
}

2. Use CopyOnWriteArrayList

Java provides thread-safe alternatives to certain collections, such as CopyOnWriteArrayList. This collection creates a copy of the array whenever it’s modified, allowing safe iteration even when the collection is being concurrently modified.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteExample {
    public static void main(String[] args) {
        List<String> list = new CopyOnWriteArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");

        // Iterating and modifying the list safely
        for (String item : list) {
            if ("B".equals(item)) {
                list.remove(item); // No ConcurrentModificationException
            }
        }
    }
}

3. Use a for Loop with Index Manipulation

If the collection is a List, using a for loop with index manipulation allows you to safely remove elements without causing the exception.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.ArrayList;
import java.util.List;

public class SafeIndexRemovalExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");

        for (int i = 0; i < list.size(); i++) {
            if ("B".equals(list.get(i))) {
                list.remove(i);
                i--; // Adjust the index after removal
            }
        }
    }
}

Conclusion

ConcurrentModificationException is a common issue that developers encounter when modifying collections during iteration. While the fail-fast mechanism helps prevent inconsistencies, it’s important to use the correct approach for modifying collections. Depending on your scenario, you can use Iterator.remove(), thread-safe collections like CopyOnWriteArrayList, or index-based iteration to avoid this exception. Understanding these strategies ensures that your code is safe and efficient when working with Java collections.

© 2024 Java Tutorial Online. All rights reserved.