__del__Iterator

Iterator.remove()

使用ArrayList时,一种很容易犯的错是在forEach遍历List时,删除其中元素

List<String> strList=new ArrayList<String>();

strList.add("1");
strList.add("2");
strList.add("3");
strList.add("4");
strList.add("5");

for(String item:strList) {
    System.out.println(item);
    if("2".equals(item)) {
        strList.remove(item);
    }
}

这样的代码会报如下异常:java.util.ConcurrentModificationException,这也很容易理解,在便利一个List的同时去修改该List是很不合理的,程序可能会报各种异常,这种行为是非法的。在ArrayList的实现上,使用了一个机制去检查这种非法操作。

注意ArrayList的add方法

public void add(E e) {
    checkForComodification();

    try {
        int i = cursor;
        ArrayList.this.add(i, e);
        cursor = i + 1;
        lastRet = -1;
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
}

其中expectedModCount为期望被修改的计数,而modCount为实际修改的计数,当两者相同时表明该List被正确操作,否则表明该List被非法操作过,此时会报异常!chechForComodification方法源码如下:

final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

该方法很简单粗暴的检查expectedModCount和modCount,如过不一致则报异常!该方法在多个地方被调用以保证List被正确的操作。

方法remove(Object)源码如下:

    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
    private void fastRemove(int index) {
        modCount++;
        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
    }

方法remove()源码如下:

        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();
            }
        }

这个地方还有一点迷,关于modcount,expectedCount几个关键性的变量是如何保证快速失败的,先停于此。

标签

评论

this is is footer