We all know that the safest "and probably only safe" way of removing an object from a collection while iterating it, is by first retrieving the Iterator
, perform a loop and remove when needed;
Iterator iter=Collection.iterator(); while(iter.hasNext()){ Object o=iter.next() if(o.equals(what i'm looking for)){ iter.remove(); } }
What I would like to understand, and unfortunately haven't found a deep technical explanation about, is how this removal is performed,
If:
for(Object o:myCollection().getObjects()){ if(o.equals(what i'm looking for)){ myCollection.remove(o); } }
Will throw a ConcurrentModificationException
, what does "in technical terms" Iterator.remove()
do? Does it removes the object, breaks the loop and restart the loop?
I see in the official documentation:
"Removes the current element. Throws
IllegalStateException
if an attempt is made to callremove()
that is not preceded by a call to next( )."
The part "removes the current element", makes me think of the exact same situation happening in a "regular" loop => (perform equality test and remove if needed), but why is the Iterator loop ConcurrentModification-safe?
An element can be removed from a Collection using the Iterator method remove(). This method removes the current element in the Collection. If the remove() method is not preceded by the next() method, then the exception IllegalStateException is thrown.
The remove method returns true if an object passed as a parameter is removed from the list. Otherwise, it returns false. The remove method returns the removed element if an index is passed. It throws IndexOutOfBoundsException if the specified index is not in range.
As per Sun , "Iterator. remove is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress."
The reason why you cannot modify a list while iterating over it is because the iterator has to know what to return for hasNext() and next().
How this is done is implementation specific, but you could have a look at the source code of ArrayList/AbstractList/LinkedList etc.
Also note that in some situations you can use some code like this as an alternative:
List<Foo> copyList = new ArrayList<>(origList); for (Foo foo : copyList){ if (condition){ origList.remove(foo); } }
But this code will probably run slightly slower because the collection has to be copied (shallow copy only) and the element to remove has to be searched.
Also note that if you're using the iterator directly it's recommended to use a for loop instead of while loop as this limits the scope of the variable:
for (Iterator<Foo> iterator = myCollection.iterator(); iterator.hasNext();){ ... }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With