Was trying to implement in-place purge on a list.
Iterator<Integer> itr = ls.iterator();
for (Integer x : ls) {
int count = 0;
while(itr.hasNext()){
if (itr.next().equals(x)) {
count++;
if (count > 1) {
itr.remove();
}
}
}
}
Exception in thread "main" java.util.ConcurrentModificationException
Iterator<Integer> iterator = numbers.iterator();
while (iterator.hasNext()) {
if (iterator.next() == 1) {
iterator.remove(); // Doesn't throw exception
}
}
However, with just one loop thought it doesn't. Why ?
what is the reasoning for this behavior
You have two iterators over ls
here:
ls.iterator()
;for (Integer x : ls)
.If you call remove()
on the first iterator, it invalidates the second iterator, meaning any invocations of next()
on the second iterator cause (or are prone to causing) a ConcurrentModificationException
to be thrown.
A possible way to do an in-place deduplication might be like this:
int dst = 0;
for (Integer x : ls) {
if (!ls.subList(0, dst).contains(x)) {
ls.set(dst++, x);
}
}
ls.subList(dst, ls.size()).clear();
This shifts elements that haven't been seen before to the left in the array; and then removes all other elements from the array afterwards.
Changing the list in the loop doesn't result in a ConcurrentModificationException
because there is no structural modification to the list.