84669 Lernen von Personen
152542 Lernen von Personen
20005 Lernen von Personen
5487 Lernen von Personen
7821 Lernen von Personen
359900 Lernen von Personen
3350 Lernen von Personen
180660 Lernen von Personen
48569 Lernen von Personen
18603 Lernen von Personen
40936 Lernen von Personen
1549 Lernen von Personen
1183 Lernen von Personen
32909 Lernen von Personen
选自《阿里巴巴JAVA开发手册》
图1代码执行情况是:解释删除1这个元素不会报错,但是删除2这个元素报错了,这个情况如何解释?
学习是最好的投资!
从报的错误中可以知道错误的来源 checkForComodification() ,如果要避免错误需要保持 modCount != expectedModCount 为 false 。list.remove(Object)会去调用fastRemove(int)方法,这个时候必然会去修改 modCount ,这个时候就会出现错误。Iterator<String> iterator = list.iterator() ;这个方法的实现就是返回一个内部类 Itr,(迭代的过程都是使用的这个类),但是为什么这个 iterator.remove() 不会出现错误了,原因在与这个方法的实现是在进行实际的 ArrayList.this.remove 之前进行的 checkForComodfication 检查,remove 之后又使 expectedModCount = modCount,所以不会出现错误。
checkForComodification()
modCount != expectedModCount
false
list.remove(Object)
fastRemove(int)
modCount
Iterator<String> iterator = list.iterator()
Itr
iterator.remove()
ArrayList.this.remove
checkForComodfication
remove
expectedModCount = modCount
Itr.remove 的实现
Itr.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(); } }
如果有不对的地方请指出 @叉叉哥 @蒲柳隐逸
单线程的情况下,在遍历List时删除元素,必须要用Iterator的remove方法而不能使用List的remove方法,否则会ConcurrentModificationException。试想如果一个老师正在点整个班级所有学生的人数,而学生如果不遵守纪律一会出去一会进来,老师肯定点不下去。
多线程的情况下,参考我的一篇博客:http://xxgblog.com/2016/04/02...
首先,这涉及多线程操作,Iterator是不支持多线程操作的,List类会在内部维护一个modCount的变量,用来记录修改次数举例:ArrayList源码
protected transient int modCount = 0;
每生成一个Iterator,Iterator就会记录该modCount,每次调用next()方法就会将该记录与外部类List的modCount进行对比,发现不相等就会抛出多线程编辑异常。
为什么这么做呢?我的理解是你创建了一个迭代器,该迭代器和要遍历的集合的内容是紧耦合的,意思就是这个迭代器对应的集合内容就是当前的内容,我肯定不会希望在我冒泡排序的时候,还有线程在向我的集合里插入数据对吧?所以Java用了这种简单的处理机制来禁止遍历时修改集合。
至于为什么删除“1”就可以呢,原因在于foreach和迭代器的hasNext()方法,foreach这个语法糖,实际上就是
while(itr.hasNext()){ itr.next() }
所以每次循环都会先执行hasNext(),那么看看ArrayList的hasNext()是怎么写的:
public boolean hasNext() { return cursor != size; }
cursor是用于标记迭代器位置的变量,该变量由0开始,每次调用next执行+1操作,于是:你的代码在执行删除“1”后,size=1,cursor=1,此时hasNext()返回false,结束循环,因此你的迭代器并没有调用next查找第二个元素,也就无从检测modCount了,因此也不会出现多线程修改异常但当你删除“2”时,迭代器调用了两次next,此时size=1,cursor=2,hasNext()返回true,于是迭代器傻乎乎的就又去调用了一次next(),因此也引发了modCount不相等,抛出多线程修改的异常。
当你的集合有三个元素的时候,你就会神奇的发现,删除“1”是会抛出异常的,但删除“2”就没有问题了,究其原因,和上面的程序执行顺序是一致的。
因为你在对元素进行增删的时候集合中的数量就改变了,那么在遍历的时候就有可能会出现问题.比如一个集合有10个元素,那就应该要遍历10次,当你对增加或删除了一个元素,遍历的次数就不对,所以会报错
倒序删除就可以了,反正list尽量不要remove。可以加delete标记
文档中那个黄色的说明很有意思。
这个例子的执行结果会出乎大家的意料,那么试下把“1”换成“2”,会是同样的结果吗?
这个还是要看ArrayList的源码,一看便知。
ArrayList
倒序删除就可以了
ArrayList不是线程安全的,这样相当于你在遍历的时候修改了List。ArrayList在这种情况下是会抛出并发修改异常的。
从报的错误中可以知道错误的来源
checkForComodification()
,如果要避免错误需要保持modCount != expectedModCount
为false
。list.remove(Object)
会去调用fastRemove(int)
方法,这个时候必然会去修改modCount
,这个时候就会出现错误。Iterator<String> iterator = list.iterator()
;这个方法的实现就是返回一个内部类Itr
,(迭代的过程都是使用的这个类),但是为什么这个iterator.remove()
不会出现错误了,原因在与这个方法的实现是在进行实际的ArrayList.this.remove
之前进行的checkForComodfication
检查,remove
之后又使expectedModCount = modCount
,所以不会出现错误。Itr.remove
的实现如果有不对的地方请指出 @叉叉哥 @蒲柳隐逸
单线程的情况下,在遍历List时删除元素,必须要用Iterator的remove方法而不能使用List的remove方法,否则会ConcurrentModificationException。试想如果一个老师正在点整个班级所有学生的人数,而学生如果不遵守纪律一会出去一会进来,老师肯定点不下去。
多线程的情况下,参考我的一篇博客:http://xxgblog.com/2016/04/02...
首先,这涉及多线程操作,Iterator是不支持多线程操作的,List类会在内部维护一个modCount的变量,用来记录修改次数
举例:ArrayList源码
每生成一个Iterator,Iterator就会记录该modCount,每次调用next()方法就会将该记录与外部类List的modCount进行对比,发现不相等就会抛出多线程编辑异常。
为什么这么做呢?我的理解是你创建了一个迭代器,该迭代器和要遍历的集合的内容是紧耦合的,意思就是这个迭代器对应的集合内容就是当前的内容,我肯定不会希望在我冒泡排序的时候,还有线程在向我的集合里插入数据对吧?所以Java用了这种简单的处理机制来禁止遍历时修改集合。
至于为什么删除“1”就可以呢,原因在于foreach和迭代器的hasNext()方法,foreach这个语法糖,实际上就是
所以每次循环都会先执行hasNext(),那么看看ArrayList的hasNext()是怎么写的:
cursor是用于标记迭代器位置的变量,该变量由0开始,每次调用next执行+1操作,于是:
你的代码在执行删除“1”后,size=1,cursor=1,此时hasNext()返回false,结束循环,因此你的迭代器并没有调用next查找第二个元素,也就无从检测modCount了,因此也不会出现多线程修改异常
但当你删除“2”时,迭代器调用了两次next,此时size=1,cursor=2,hasNext()返回true,于是迭代器傻乎乎的就又去调用了一次next(),因此也引发了modCount不相等,抛出多线程修改的异常。
当你的集合有三个元素的时候,你就会神奇的发现,删除“1”是会抛出异常的,但删除“2”就没有问题了,究其原因,和上面的程序执行顺序是一致的。
因为你在对元素进行增删的时候集合中的数量就改变了,那么在遍历的时候就有可能会出现问题.比如一个集合有10个元素,那就应该要遍历10次,当你对增加或删除了一个元素,遍历的次数就不对,所以会报错
倒序删除就可以了,反正list尽量不要remove。可以加delete标记
文档中那个黄色的说明很有意思。
这个还是要看
ArrayList
的源码,一看便知。倒序删除就可以了
ArrayList不是线程安全的,这样相当于你在遍历的时候修改了List。
ArrayList在这种情况下是会抛出并发修改异常的。