ArrayList

2020-05-17  本文已影响0人  森林中大鸟

ArrayList foreach删除元素报错分析

List<String> a = new ArrayList<String>(); 
    a.add("1");
    a.add("2");
    for (String temp : a) { 
        if("1".equals(temp)){
            a.remove(temp); 
    } 
} 

以上代码对应class文件如下:

List a = new ArrayList();
a.add("1");
a.add("2");
Iterator i$ = a.iterator();
do
{
    if(!i$.hasNext())
        break;
    String temp = (String)i$.next();
    if("1".equals(temp))
        a.remove(temp);
} while(true);

场景一

 List<String> a = new ArrayList<String>(); 
 a.add("1");
 a.add("2");
 for (String temp : a) { 
    if("1".equals(temp)){
         a.remove(temp); 
     } 
 } 

执行结果

删除不会报错,但是循环只走了一次就结束了。

原因

for循环实际相当于使用迭代器遍历,在第一次循环时,执行完next()方法后游标置为1,即如下代码中第9行 cursor = 1

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

接着执行remove(),执行成功后 size-1。
进行下次循环时执行hasNext()判断是否存在下一个元素时 满足cursor!=size 为true
,因此循环结束,代码如下:

public boolean hasNext() {
    return cursor != size;
}

场景二

 List<String> a = new ArrayList<String>(); 
 a.add("1");
 a.add("2");
 for (String temp : a) { 
    if("2".equals(temp)){
         a.remove(temp); 
     } 
 } 

执行结果

删除之后,报错。

原因

for 在第二次循环中,执行完remove(),size=1,此时因为循环执行过两次,因此 此时cursor = 2,在进行第三次循环前 会执行 hasNext(),此时size != cursor 成立,导致 hasNext() 结果为true ,进入循环,然后执行next()方法。
next()方法会判断修改次数与预期修改次数是否相等,因为直接调用ArrayList的remove方法修改了modCount(+1)但不会修改得迭代器中的 expectedModCount的值,因此 出现
ConcurrentModificationException

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

猜你喜欢

热点阅读