Intent here is to check if you are aware of technique for modifying the collection structure while iterating through it. If we call collection.remove()
from within the for loop then ConcurrentModificationException
will be thrown by the JVM at runtime.
Removing elements while iterating over a Java Collection
Upasana | December 16, 2019 | 2 min read | 1,035 views | Multithreading and Concurrency
So lets consider the below naive approach for removing elements from a collection while iterating over it:
import java.util.ArrayList;
import java.util.List;
import static java.util.Arrays.asList;
public class Test {
public void removeFromCollection(List marks) {
for (Integer mark : marks) {
if (mark < 40)
marks.remove(mark); (1)
}
}
public static void main(String[] args) {
Test test = new Test();
test.removeFromCollection(new ArrayList(asList(10,20,50,60)));
}
}
1 | this line will throw java.util.ConcurrentModificationException |
It is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. Iterators that do this are known as <i>fail-fast</i> iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Actually, the right way to handle such scenario is to use Iterator to remove the element from the underlying Collection while iterating over it. ConcurrentModificationException
is thrown because the for loop internally creates a fail-fast iterator which throws exception whenever it finds any structural modification in the underlying data structure (ArrayList in this case).
What is Structural Modification
Java Docs
A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely changing the values associated with a key that an instance already contains is not a structural modification.
Further, the structural modification could happen either from single thread or from multiple threads. The behavior of ArrayList would be different in both the cases as mentioned below.
The correct implementation for removal method would look like this:
class Scratch {
public void removeFromCollection(List marks) {
for (Iterator iterator = marks.iterator(); iterator.hasNext(); ) {
Integer mark = iterator.next();
if (mark < 40)
iterator.remove();
}
}
}
If you are facing this exception in a multi-threading scenario, then better to consider using fail-safe iterators.
Java 8 approach
Java 8 provides a safer method to conditionally remove items from stream using a filter
List<String> names = new ArrayList(asList("munish","ravneesh", "rajneesh"));
names.removeIf(name -> "munish".equalsIgnoreCase(name));
System.out.println("names = " + names);
Though lambda makes removal quite compact, but the operation is not thread-safe and must not be used in multi-threaded environment without explicit synchronization in place.
Top articles in this category:
- Fail-Safe vs Fail-Fast Iterator in Java Collections Framework
- ConcurrentModificationException in Java
- Blocking Queue implementation in Java
- Discuss internals of a ConcurrentHashmap (CHM) in Java
- Custom Thread pool implementation in Java
- Http download using Java NIO FileChannel
- How will you increment each element of an Integer array, using parallel operation