Changing a collection while traversing might lead to unexpected errors
TL;DR: Don't modify collections while traversing them
-
Unexpected Results
-
Concurrency problems
-
Avoid altering the collections
-
Make collection copies
We over-optimize our solutions with the prejudice that copying collections is expensive.
This is not true for small and medium-size collections.
Languages iterate collections in many different ways.
Modifying them is generally not safe.
// here you add elements to the collection...
Collection<Integer> people = new ArrayList<>();
for (Object person : people) {
if (condition(person)) {
people.remove(person);
}
}
// You iterate AND remove elements, elements,
// risking skipping other candidates for removalCollection<Integer> people = new ArrayList<>();
// Here you add elements to the collection...
List<Object> iterationPeople = ImmutableList.copyOf(people);
for (Object person : iterationPeople) {
if (condition(person)) {
people.remove(person);
}
}
// You iterate a copy and remove it from the original
coll.removeIf(currentIndex -> currentIndex == 5);
// Or use language tools (if available)[X] Semi Automatic
Many languages provide control both in compile and run-time
- Fail-Fast
This is something we learn in our first courses.
It happens a lot in the industry and real-world software
Code Smell 53 - Explicit Iteration
Code Smell 134 - Specialized Business Collections
Photo by Christine Roy on Unsplash
Bugs are bugs. You write code with bugs because you do. If itβs a safe language in the sense of run-time safe, the operating system crashes instead of doing a buffer overflow in a way thatβs exploitable.
Ken Thompson
Software Engineering Great Quotes
This article is part of the CodeSmell Series.
