When we operate on the collection, we will find that if we use the iterator to iterate, but during the iterator process if we use the collection object to delete, add, or empty the collection stored objects, then the program will raise an exception, such as the following code:


public class IteratorTest {
    public static void main(String[] args) {
        ArrayList<String>list = new ArrayList<String>(Arrays.asList("a"."b"."c"."d"));
        Iterator<String>iter = list.iterator();
        while(iter.hasNext()){
            String s = iter.next();
                if(s.equals("a")){ list.remove(0); // iter.remove(); }}}}Copy the code
This program will raise the following exception:
Exception in thread "main" java.util.ConcurrentModificationException    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)    at java.util.ArrayList$Itr.next(Unknown Source)    at IteratorTest.main(IteratorTest.java:13)Copy the code
But if I comment it out
 list.remove(0);Copy the code
Remove the iter. Remove (); annotationCopy the code
So the program runs without a problem, why is that?


Iterator supports safely removing objects from the source collection by calling remove() on Iterator. The advantage is to avoid ConcurrentModifiedException, this exception as the name implies: when open the Iterator iterative collection, at the same time, in the collection.


Some collections do not allow elements to be removed or added during iteration, but it is safe to call Iterator’s remove() method.
So why is Iterator safe to delete?
First let’s look at what happens when we generate an iterator.
public Iterator<E> iterator() {
        return new Itr();
    }Copy the code
For example, ArrayList returns an Itr object when iterator is called. Let’s look at the Itr object:
 private class Itr implements Iterator<E> {
        int cursor;       // index of next element to returnint lastRet = -1; // index of last element returned; - 1if no such
        int expectedModCount = modCount;Copy the code
This is the Itr object with several class member variables, where we see a field called expectedModCount. What does it do? Let’s look at the remove function
 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(); 
           } 
       } 
       final void checkForComodification() {
            if(modCount ! = expectedModCount) throw new ConcurrentModificationException(); }Copy the code
As shown in the source code, we can see that the Itr removes first by checking for lastRet, which makes sense, to check for the last element. Then the checkForComodification check is carried out. The specific operation is as shown in the above function, that is, check whether modCount and expectedModCount are equal. If they are equal, it will be ok. So what does modCount do?
public E remove(int index) {
        rangeCheck(index);
        modCount++;
        E oldValue = elementData(index);
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,                             numMoved);        elementData[--size] = null; // clear to let GC do its work        return oldValue;    }Copy the code
This is the remove function of ArrayList, which increments modCount by one every time it executes remove. Not only does it increments modCount by one, but the add (), clear () functions also increments modCount by one. So what does modCount do? It is essentially a variable that records the version of the ArrayList and increments it with one each time it is operated on, indicating that a new operation has been performed. Now, back to the original question, why does a list that deletes an element iterator get an error? When the iterator is obtained, the expectedModCount in the iterator is initialized to modCount, and if the ArrayList object is removed directly, the value of modCount will be changed (incrementing by one). ExpectedModCount! Is found when the checkForComodification check is performed during iterator iteration. =modCount, that is, if the current version is found to be different from the version recorded by the iterator, then there must be a problem during the iteration. In this case, the previous exception will be reported.


So, let’s take a look at why the Itr deletion can be safely deleted, no error? In his remove function you can see the following sentence, first of all, the ArrayList’s remove function is called
ArrayList.this.remove(lastRet)Copy the code
But after calling this function, he does the following
expectedModCount = modCount;Copy the code
The iterator is told the latest version number, so it will not report an error when checking for exceptions because they are equal. So this explains the problem raised by the title, and it is worth noting that for add operations, it is not allowed during the entire iterator iteration. The same is true for other sets (maps/sets) that use iterators.


When iterating over a Collection or Map using a Fail-fast iterator and attempting to modify the contents of a Collection/Map directly, even if running in a single thread, Java. Util. ConcurrentModificationException exception will be thrown.


Iterator works on a separate thread and has a mutex lock.


After the Iterator is created, it creates a single indexed table that points to the original object. When the number of original objects changes, the contents of the index table do not change synchronously. Therefore, when the index pointer moves backwards, the object to be iterated cannot be found. So the Iterator thrown immediately in accordance with the principle of fail – fast Java. Util. ConcurrentModificationException anomalies.


So the Iterator does not allow the iterated object to be changed while working.


But you can remove objects using Iterator’s own method, remove(). Iterator.remove() maintains index consistency while removing the current iteration.
Another interesting point:
What’s interesting is if your Collection/Map object is only one element, actual ConcurrentModificationException exception will not be thrown. That’s why javadoc pointed out that it would be wrong to write a program that ‖ ‖ this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.