Programming
Collection Manipulation
Iteration
Data Structures
Code Optimization

Remove elements from collection while iterating

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Iterating over a collection and modifying its contents during iteration is a common task in software development. However, this process can be inherently problematic as modifications such as removing elements can disrupt the iterator and potentially lead to errors or unexpected behavior. This article explains the challenges and solutions associated with removing elements from a collection while iterating through it, using Java as the primary example.

The Problem

The primary issue when trying to remove items from a collection during iteration in Java is the ConcurrentModificationException. This exception is thrown when an attempt is made to modify a collection while it is being iterated, except through the iterator's own remove method. This situation arises because most iterators are fail-fast, detecting any modification to the collection structure that it wasn't expecting.

Solutions

1. Using Iterator's remove() Method

The safest and most common method to remove elements from a collection during iteration is through the Iterator’s own remove() method. This method ensures that the collection's size is adjusted, and the iterator's state is valid after the removal. Here’s an example using Java:

java
1List<String> list = new ArrayList<>(Arrays.asList("Apple", "Banana", "Cherry"));
2Iterator<String> itr = list.iterator();
3while (itr.hasNext()) {
4    String fruit = itr.next();
5    if (fruit.equals("Banana")) {
6        itr.remove();  // Remove element using Iterator's remove method
7    }
8}

In this example, "Banana" is safely removed from the list without causing a ConcurrentModificationException.

2. Using Concurrent Collections

If the collection is intended to be accessed and modified by multiple threads, using concurrent collections like CopyOnWriteArrayList or ConcurrentHashMap might be preferable. These collections have thread-safe iterators that handle modifications by making fresh copies of the underlying data structures.

Example using CopyOnWriteArrayList:

java
1CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(Arrays.asList("Apple", "Banana", "Cherry"));
2for (String fruit : list) {
3    if (fruit.equals("Banana")) {
4        list.remove(fruit);  // Safe removal during iteration
5    }
6}

3. Collecting Items to Remove Later

Another safe approach is first to gather items that need to be removed in a separate collection and then remove these outside the loop. This method is straightforward and works with all types of collections:

java
1List<String> list = new ArrayList<>(Arrays.asList("Apple", "Banana", "Cherry"));
2List<String> toRemove = new ArrayList<>();
3
4for (String fruit : list) {
5    if (fruit.equals("Banana")) {
6        toRemove.add(fruit);
7    }
8}
9
10list.removeAll(toRemove);

Summary Table

MethodCollection TypeThread SafeNotes
Iterator’s remove()General purposeNoSafest for single-thread, direct modification
Concurrent Collection MethodsConcurrent collectionsYesHandles multi-threading scenarios
Collect and Remove After IterationGeneral purposeNoSimple and effective, but requires additional space

Additional Considerations

  • Performance: Using concurrent collections or creating a separate list for items to remove can have performance implications due to the overhead of managing the additional complexity or data structures.
  • Best Practices: Favor immutability where possible; an immutable data structure or an effectively immutable pattern can sidestep many of these iteration issues.
  • Library Support: Some libraries like Apache Commons and Google Guava provide additional collection utilities that can simplify common tasks including safely removing items.

In summary, removing elements from a collection while iterating requires careful handling to avoid errors and ensure consistent behavior. Java provides multiple ways to handle this, each suitable for different scenarios, ensuring that developers can choose the best strategy based on their specific requirements.


Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.