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
- Iterator之remove情况分析之一报错原因
- Iterator 循环 List 使用remove方法报错的分析与解决办法。
- NoClassDefDoundErr报错原因之一
- Iterator 循环 List remove元素报错的解决办法
- 头文件报错情况之一
- hibernate.cfg.xml报错原因之一
- C4146报错原因分析
- tomcat迁移到weblogic web.xml报错原因之一
- 点击“下一页”页面异常报错问题,原因之一
- Android查询电话薄报错原因分析
- Android调用webService报错原因分析
- Python报错信息与原因分析
- java之iterator分析
- MySQL server has gone away报错原因分析
- MySQL server has gone away报错原因分析
- MySQL server has gone away报错原因分析
- iOS 绘图时使用 UIGraphicsGetCurrentContext() 报错的原因分析
- MySQL server has gone away报错原因分析
- Codechef Aug2017 #Walks on the binary tree -- 主席树+Hash
- js转换Date日期格式
- sys.stdout.flush()
- iOS开发 CGContextRef画图使用
- 第一个Java程序,输出“HelloWorld”。
- Iterator之remove情况分析之一报错原因
- 视频内容谁来保护?阿里云视频加密技术大揭秘,打造云上视频安全体系
- 判断是否是相同二叉树&&判断是否是对称树
- What is JSON Wire Protocol?
- xutils3图片加载详解
- 安装ffmpeg
- 广州本爱信息科技有限公司是骗子吗?真相揭秘
- 9. Palindrome Number(回文数字 eg:12321) —— Java
- UI控件之UISlider简单图片放大与缩小的应用