How Iterator's remove method actually remove an object

94,562

Solution 1

How exactly Iterator removes elements depends on its implementation, which may be different for different Collections. Definitely it doesn't break the loop you're in. I've just looked how ArrayList iterator is implemented and here's the code:

public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    checkForComodification();

    try {
        ArrayList.this.remove(lastRet);
        cursor = lastRet;
        lastRet = -1;
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
}

So it checks for concurrent modifications, removes element using public ArrayList remove method, and increments counter of list modifications so ConcurrentModificationException won't be thrown at next iteration.

Solution 2

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();){
...
}
Share:
94,562
JBoy
Author by

JBoy

Beginner java/jsp developer

Updated on February 09, 2020

Comments

  • JBoy
    JBoy over 4 years

    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 call remove() 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?