ArrayList在foreach循环的时候remove元素报错

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Kevin_King1992/article/details/79888918

示例代码:

public class ArrayListTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("hello");
        list.add("hello1");
        list.add("hello2");
        list.add("hello3");
        list.add("hello4");
        list.add("hello5");
        for(String s : list){
            list.remove("hello2");
        }
    }
}

报错结果:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)
    at com.collection.list.ArrayListTest.main(ArrayListTest.java:18)

再看这个问题之前大家先来了解一下foreach的本质是什么,
参考此博文:https://blog.csdn.net/wangjun5159/article/details/61415263,foreach只是语法糖,本质还是
for(Iterator i = a . i t e r a t o r ( ) ; i .hasNext(); System.out.print(temp));

然后追踪栈轨迹看看源码:

@SuppressWarnings("unchecked")
public E next() {
    checkForComodification();//问题出在这行代码,然后看这个方法是什么?
    int i = cursor;
    if (i >= size)
        throw new NoSuchElementException();
    Object[] elementData = ArrayList.this.elementData;
    if (i >= elementData.length)
        throw new ConcurrentModificationException();
    cursor = i + 1;
    return (E) elementData[lastRet = i];
}
final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

上面两个方法都是private class Itr implements Iterator 这个迭代器实现类的方法。有上面两个方法可以明显的看出 if (modCount != expectedModCount)这个判断上,是这两个值不相等导致抛出了异常,那么这两个值又是什么呢?

//The number of times this list has been <i>structurally modified</i>.
protected transient int modCount = 0;

private class Itr implements Iterator<E> {
   int cursor;       // index of next element to return
   int lastRet = -1; // index of last element returned; -1 if no such
   int expectedModCount = modCount;
}

modCount变量是ArrayList继承的抽象类AbstractList中一个变量,它表示的是对list的修改次数,而迭代器中的expectedModCount 在初始的时候,将modCount赋给了expectedModCount ,通过上面foreach我们看得到迭代器是在已进入for循环的时候初始的这时候modCount是未进行修改的,但是接下来remove有干了什么呢?

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

如上代码,看到remove的元素如果存在的话会进入下面这个方法:

private void fastRemove(int index) {
    modCount++;//在这里操作了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
}

看到这里我们明白了什么时候改变了modCount导致和expectedModCount 不一致抛出了错误。

猜你喜欢

转载自blog.csdn.net/Kevin_King1992/article/details/79888918
今日推荐