Skip to content
Advertisement

Removing elements while iterating. removeIf result in ConcurrentModificationException

I’m trying to remove elements from a set (someObjectSet) while looping through it. As I googled, using removeIf should avoid ConcurrentModificationException in this case. However this doesn’t work for me.

Did google lie to me (or I misundertood it), or I’m not using removeIf correctly?

Set<SomeObject> someObjectSet = new HashSet<>();
someObjectSet.add(obj1);
someObjectSet.add(obj2);
someObjectSet.add(obj3);

for (SomeObject obj : someObjectSet ){
    ...
    someObjectSet.removeIf(ele -> if ele satisfies some condition)
}

The reason I want to do removeif inside the loop is that, in each loop, it can be determined that some other elements of the set no longer need to go in the loop, therefore I’m removing it so that the for loop won’t pick them up again.

For example,
In loop1, obj1 gets picked.
Then in the same loop it finds out obj2 no longer needs to be processed => remove obj2 from the set.
In loop2, instead of obj2, obj3 is picked up

Thanks in advance!

Advertisement

Answer

Don’t iterate and removeIf using elements of your iteration. Beside the problem you’re experiencing right now, those calls amount to iterating through the entire collection for each element of the collection (so you’re still removing from the collection while iterating, which explains the exception!).

removeIf iterates for you, so all you need is a predicate of SomeObject:

//no loop
someObjectSet.removeIf(ele -> if ele satisfies some condition);

Where ele -> if ele satisfies some condition is the condition that each SomeObject element will be tested against (the ones passing the test will be removed). forEach will orchestrate the test on all elements in someObjectSet, you don’t need to do that.


If you’re having a secondary condition based on which you want to remove elements, then you can compose predicates (with or), something like in this example:

Set<Integer> set = new HashSet<>(Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9));

Predicate<Integer> predicate = s -> s % 2 == 0;
Predicate<Integer> predicate2 = predicate.or(s -> s % 3 == 0);
set.removeIf(predicate2);

// Test with set.removeIf(predicate);
// then with set.removeIf(predicate2);
// and compare results
Advertisement