Card 06/ 08
All 8 cards
GotchaDifficulty: Advanced1 min
Why Removing Inside a for-each Throws
A loop that removes the cancelled orders from a list. It throws on the second removal, with an exception whose name mentions concurrency in code that has one thread.
for (String ref : refs) {
if (ref.startsWith("X")) {
refs.remove(ref);
}
}Exception in thread "main" java.util.ConcurrentModificationExceptionThe enhanced for uses an iterator, and the iterator keeps a count of how many times the list has been structurally changed. Removing through the list bumps that count without telling the iterator, so the next step notices the mismatch and refuses to continue.
Three ways out, in order of how often they are the right one.
refs.removeIf(ref -> ref.startsWith("X"));
Iterator<String> it = refs.iterator();
while (it.hasNext()) {
if (it.next().startsWith("X")) { it.remove(); }
}
List<String> kept = refs.stream().filter(ref -> !ref.startsWith("X")).toList();removeIf is one line and says what it means. The iterator's own remove is the general answer when the condition needs more than an expression. Building a new list is the right answer when the original should not change at all.