集合为什么不能在遍历的同时删除其中的元素?

问题:删除Set中的某些元素的时候,使用边遍历,边删除的方法,报以下异常:ConcurrentModificationException

ConcurrentModificationException是Java集合的一个快速失败(fail-fast)机制,防止多个线程同时修改同一个集合的元素。

集合使用迭代器删除元素代码及原理:

private abstract class HashIterator implements Iterator {
        Entry next;    // next entry to return
        int expectedModCount;    // For fast-fail
        int index;        // current slot
        Entry current;    // current entry
 
        HashIterator() {
            expectedModCount = modCount;
            if (size > 0) { // advance to first entry
                Entry[] t = table;
                while (index < t.length && (next = t[index++]) == null)
                    ;
            }
        }
 
        public final boolean hasNext() {
            return next != null;
        }
 
        final Entry nextEntry() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            Entry e = next;
            if (e == null)
                throw new NoSuchElementException();
 
            if ((next = e.next) == null) {
                Entry[] t = table;
                while (index < t.length && (next = t[index++]) == null)
                    ;
            }
        current = e;
            return e;
        }
//调用的这个方法
        public void remove() {
 
            if (current == null)
                throw new IllegalStateException();
//玄机就在这里:expectedModCount,拷贝网上找来的说明,
/** 
*在Iterator的内部有个expectedModCount 变量, 
*该变量每次初始化*Iterator的时候等于ArrayList的modCount,modCount记录了对ArrayList的结构修改次数, 
*在通过Iterator对ArrayList进行结构的修改的时候都会将expectedModCount 与modCount同步, 
*但是如果在通过Iterator访问的时候同时又通过索引的方式去修改ArrayList的结构的话, 
*由于通过索引的方式只会修改modCount不会同步修改expectedModCount 就会导致 
*modCount和expectedModCount 不相等就会抛ConcurrentModificationException, 
*这也就是Iterator的fail-fast,快速失效的。所以只要采取一种方式操作ArrayList就不会出问题, 
*当然ArrayList不是线程安全的,此处不讨论对线程问题。 
 
* http://sushe1424.iteye.com/blog/1110796
*/  
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            Object k = current.key;
            current = null;
            HashMap.this.removeEntryForKey(k);
            expectedModCount = modCount;
        }
 
    }

java中对remove方法的介绍:
remove
void remove()从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
每次调用 next 只能调用一次此方法。如果进行迭代时用调用此方法之外的其他方式修改了该
迭代器所指向的 collection,则迭代器的行为是不确定的。

参考:
https://blog.csdn.net/yin_jw/article/details/39668673
https://bbs.csdn.net/topics/390711013
http://sushe1424.iteye.com/blog/1110796

你可能感兴趣的:(数据结构)