Iterator之remove情况分析之一报错原因

来源:互联网 发布:五金淘宝店铺表示 编辑:程序博客网 时间:2024/06/03 20:05

在iterator过程中使用list.remove,报错Exception in thread "main" java.util.ConcurrentModificationException

package collect;import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class myiterator {public static void main(String[] args) {     List<String> list =new ArrayList<String>();     list.add("China");     list.add("hello");     list.add("world");     Iterator<String> it =list.iterator();     System.out.println(list.size());          int i = 0,j=0;     while (it.hasNext()) {        it.next();         i++;         list.remove("hello");        System.out.println("运行第"+i+"次");        }    }}

结果

3运行第1次Exception in thread "main" java.util.ConcurrentModificationException    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)    at java.util.ArrayList$Itr.next(Unknown Source)    at collect.myiterator.main(myiterator.java:18)

同时修改异常,就是在iterator运行过程中,因为list修改而报错的异常

源代码的角度来说:当arrarlist调用iterator的时候,返回一个Itr的引用

public Iterator<E> iterator()  {    return new Itr(null);  }

在arraylist中找到Itr的类

private class Itr    implements Iterator<E>  {    int cursor;    int lastRet = -1;    int expectedModCount = modCount;        private Itr() {}        public boolean hasNext()    {      return cursor != size;    }        public E next()    {      checkForComodification();      int i = cursor;      if (i >= size) {        throw new NoSuchElementException();      }      Object[] arrayOfObject = elementData;      if (i >= arrayOfObject.length) {        throw new ConcurrentModificationException();      }      cursor = (i + 1);      return (E)arrayOfObject[(lastRet = i)];    }        public void remove()    {      if (lastRet < 0) {        throw new IllegalStateException();      }      checkForComodification();      try      {        remove(lastRet);        cursor = lastRet;        lastRet = -1;        expectedModCount = modCount;      }      catch (IndexOutOfBoundsException localIndexOutOfBoundsException)      {        throw new ConcurrentModificationException();      }    }

 

checkForComodification();这个方法

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

判断一下modCount != expectedModCount是否相等,不等的话抛出ConcurrentModificationException();

modCount属于 AbstractList<E>类的protected transient int modCount = 0;初始为0

expectedModCount属于ArrayList<E>下面的Itr类的

int expectedModCount = modCount;

当arraylist调用remove方法时,调用的是arraylist下面的remove跟fastRemove对应方法

public E remove(int paramInt)  {    rangeCheck(paramInt);    modCount += 1;    Object localObject = elementData(paramInt);    int i = size - paramInt - 1;    if (i > 0) {      System.arraycopy(elementData, paramInt + 1, elementData, paramInt, i);    }    elementData[(--size)] = null;    return (E)localObject;  }    public boolean remove(Object paramObject)  {    int i;    if (paramObject == null) {      for (i = 0; i < size; i++) {        if (elementData[i] == null)        {          fastRemove(i);          return true;        }      }    } else {      for (i = 0; i < size; i++) {        if (paramObject.equals(elementData[i]))        {          fastRemove(i);          return true;        }      }    }    return false;  }    private void fastRemove(int paramInt)  {    modCount += 1;    int i = size - paramInt - 1;    if (i > 0) {      System.arraycopy(elementData, paramInt + 1, elementData, paramInt, i);    }    elementData[(--size)] = null;  }

 

当调用remove(int paramInt)时,modCount+= 1;会+1改变modCount 的值

当调用remove(Object paramObject) ,会调用fastRemove(int paramInt) 接着modCount += 1;会+1改变modCount 的值

总之,ArrayList<E>下面的remove方法会改变modCount的值,remove一次,使其+1一次

总结:现在从头看一下,当Iterator<String> it =list.iterator();时,创建一个Itr引用

并且内部int expectedModCount = modCount;,来自于AbstractList<E>   的protected transient int modCount = 0;

现在expectedModCount跟modCount都等于0,在执行完arraylist的remove方法后modCount值+1,

然后程序执行iterator.next(); 其中checkForComodification()判断expectedModCount跟modCount值不等,然后thrownew ConcurrentModificationException();

同样在iterator里面进行list.add也会导致modCount值+1  报错

add方法每次都会ensureCapacityInternal确保容量够用

public boolean add(E paramE)  {    ensureCapacityInternal(size + 1);    elementData[(size++)] = paramE;    return true;  }    public void add(int paramInt, E paramE)  {    rangeCheckForAdd(paramInt);    ensureCapacityInternal(size + 1);    System.arraycopy(elementData, paramInt, elementData, paramInt + 1, size - paramInt);    elementData[paramInt] = paramE;    size += 1;  }

然后这里面就会执行modCount += 1;

private void ensureCapacityInternal(int paramInt)  {    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {      paramInt = Math.max(10, paramInt);    }    ensureExplicitCapacity(paramInt);  }    private void ensureExplicitCapacity(int paramInt)  {    modCount += 1;    if (paramInt - elementData.length > 0) {      grow(paramInt);    }  }

这里面是判断是否存在对象,

假如list里面什么都没有因为iterator.hasNext()都进不去,在iterator里面可以写list.add方法,不过东西加入到list的里面,输出结果还是为空,

如果list存在值这时进入iterator遍历,先判断是否存在,不过hasNext()判断过了,肯定存在

if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {      paramInt = Math.max(10, paramInt);    }

所以一定执行ensureExplicitCapacity,modCount+= 1;,导致iterator里面list.add失败

相关内容:

forEach内部实现原理,也无法执行list.add与remove分析

如何实现在iterator内部remove