Best Practices to Avoid ConcurrentModificationException in Java: Iterating and Removing Elements from ArrayList

Nov 13, 2025 · Programming · 14 views · 7.8

Keywords: Java | ConcurrentModificationException | ArrayList | Iterator | Element Removal

Abstract: This article provides an in-depth analysis of the ConcurrentModificationException mechanism in Java, focusing on the root causes when removing elements during ArrayList iteration. By comparing multiple solutions, it详细介绍介绍了 the best practices including using iterator's remove method, removeAll method, and Java 8's removeIf method, with complete code examples and performance comparisons to help developers effectively avoid this common issue.

Mechanism of ConcurrentModificationException

In the Java Collections Framework, ConcurrentModificationException is a common runtime exception that typically occurs when using iterators to traverse collections. This exception is designed to implement the "fail-fast" mechanism, ensuring that collection structures are not unexpectedly modified during iteration.

When using enhanced for loops to traverse ArrayList, the Java compiler automatically creates iterator objects at the underlying level. The iterator records the modification count (modCount) of the collection during initialization and checks whether this value has changed every time the next() method is called. If it detects that the collection has been modified during iteration, it immediately throws ConcurrentModificationException.

Problem Scenario Analysis

Consider the following typical scenario: removing elements through the collection's own remove() method while traversing an ArrayList. In this case, the collection's modification count increases, but the iterator is unaware of this change, leading to inconsistent state detection when the next() method is called again.

public class Test {
    private ArrayList<A> abc = new ArrayList<A>();

    public void doStuff() {
        for (A a : abc) {
            a.doSomething(); // may call removeA method
        }
    }

    public void removeA(A a) {
        abc.remove(a); // directly using collection's remove method
    }
}

In the above code, when the doStuff() method is iterating through the abc list, if a.doSomething() indirectly calls the removeA() method, it will trigger ConcurrentModificationException.

Solution Comparison

Solution 1: Using Iterator's remove Method

The most direct and recommended solution is to use the iterator's own remove() method. This approach requires abandoning enhanced for loops and using explicit iterator traversal instead.

public void doStuff() {
    Iterator<A> iterator = abc.iterator();
    while (iterator.hasNext()) {
        A a = iterator.next();
        if (removalCondition) {
            iterator.remove(); // using iterator's remove method
        } else {
            a.doSomething();
        }
    }
}

The iterator's remove() method synchronizes the iterator's state after removing elements, ensuring that concurrent modification exceptions are not triggered. This method is suitable for scenarios where elements need to be dynamically deleted based on conditions during traversal.

Solution 2: Collecting Elements for Batch Removal

Another effective approach is to first collect all elements that need to be removed, then remove them all at once after traversal is complete.

public void doStuff() {
    List<A> elementsToRemove = new ArrayList<>();
    
    for (A a : abc) {
        if (removalCondition) {
            elementsToRemove.add(a);
        } else {
            a.doSomething();
        }
    }
    
    abc.removeAll(elementsToRemove);
}

The advantage of this method is that it maintains code readability, especially in complex business logic. The drawback is that it requires additional space to store elements to be removed, which may impact performance for large collections.

Solution 3: Using Java 8's removeIf Method

For Java 8 and higher versions, the removeIf() method provides a more concise solution.

public void doStuff() {
    abc.removeIf(a -> {
        boolean shouldRemove = removalCondition;
        if (!shouldRemove) {
            a.doSomething();
        }
        return shouldRemove;
    });
}

The removeIf() method is implemented internally using iterators, offering the advantages of type safety and functional programming. This method is particularly suitable for predicate-based removal operations.

Performance Analysis and Selection Recommendations

When choosing a specific solution, the following factors should be considered:

For multi-threaded environments, it is recommended to use concurrent collection classes such as CopyOnWriteArrayList, which are designed with concurrent modification issues in mind.

Practical Application Example

The following is a complete example demonstrating how to safely remove elements with length greater than 5 from a string list:

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("apple");
        list.add("banana");
        list.add("cat");
        list.add("elephant");
        
        // Using iterator for safe removal
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String value = iterator.next();
            if (value.length() > 5) {
                iterator.remove();
            }
        }
        
        System.out.println(list); // Output: [cat]
    }
}

Conclusion

The key to avoiding ConcurrentModificationException lies in understanding how iterators work and the modification mechanism of collections. By using the iterator's remove() method, batch removal strategies, or Java 8's removeIf() method, elements can be safely removed during traversal. In actual development, the most suitable solution should be selected based on specific requirements to ensure code robustness and maintainability.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.