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