迭代器使用过程中为什么抛出ConcurrentModificationException

出现的场景:在迭代器对集合进行遍历的同时,集合本身进行变更操作(add(), remove(), set())。

当正常调用时:

import java.util.ArrayList;
import java.util.Iterator;

public class TestDemo {
    public static void main(String[] args) {
        ArrayList<Integer> a = new ArrayList<>();
        a.add(1);
        a.add(3);
        a.add(5);
        a.add(6);
        Iterator<Integer> iterator = a.iterator();
        while (iterator.hasNext()){
            System.out.print(iterator.next()+" ");
        }
    }
}

结果:

当调用interator()接口里面的remove()操作时:

结果:

当调用ArrayList的对象下的remove()或者add();

或者

便会报错:

那么为何会出现这种情况呢?

首先我们应该知道,ArrayList底层的modCount这个属性,这也是个版本记录号每对ArrayList进行一次增删改操作,都会进行modCount++操作。并且在迭代器的使用中,会将当前的modCount的值赋给expectedModCount迭代器的这个属性。

我们先来看看得ArrayList内地迭代器的部分源码:

可以看到每次Iterator的对象调用next()操作时,都会调用checkForComodification()的方法,具体我们来看看这个方法。

再来看看迭代器中的remove()方法:

可以看到迭代器中的remove()方法虽然也是用的ArrayList的remove()方法,正如前面所说,那也会对modCount的值进行改变,但是关键就在于expectedModCount = modCount,它会将改变的值重新赋给expectedModCount。然后每次用完迭代器中的remove()方法后,就算再次用nex()的方法,调用checkForComodification()方法,就不会抛出异常。但是如果直接用ArrayList的对象调用增删改的方法,modCount值得改变,不会引起expectedModCount值的变化,再次调用迭代器,调用到checkForComodification()方法时,便会抛出ConcurrentModificationException的错误。

总的来说,在调用迭代器的时候,就用迭代器的remove()方法,否则就会出现错误,还有迭代器的一个对象只能进行一次迭代,要多次迭代,,便要创建多个对象。

原文地址:https://www.cnblogs.com/128-cdy/p/12031571.html

时间: 2024-10-09 04:24:30

迭代器使用过程中为什么抛出ConcurrentModificationException的相关文章

java修改集合抛出ConcurrentModificationException异常

测试代码为: public static void main(String[] args) { List<String> strList = new ArrayList<String>(); strList.add("1"); strList.add("2"); strList.add("3"); strList.add("4"); for(String str:strList){ if(str.equ

0xe7f001f0!?NDK调试过程,无故抛出SIGSEGV。

arm调试过程,如果抛一个SIGSEGV,地址在 0xe7f001f0 附近,原因居然是因为我在调试.当我使用n指令跳到下一行代码时,往往变成了continue指令一样地执行.还不确定地抛出SIGSEGV(addr:0xe7f00XXX),使用程序直接崩溃不能继续调试下去.查看寄存器发现的确有某个rN的寄存器被诡异地修改了.多次归纳后发现,都在调用虚函数时抛出SIGSEGV(addr:0xe7f00XXX),不论何处何种逻辑下,这个被神修改的寄存器的值都是0xe7f00XXX,在反编译逻辑中是要

C# 中异常抛出捕获机制--throw / try,catch,finally

try { messagebox.show("true"); } catch { messagebox.show("false"); } finally { messagebox.show("finally"); } notes:      抛出异常用 throw new exception,捕获异常用 try..catch..finally try ... catch 的目的是解决程序在出现错误时无法继续执行下去的问题. try不一定只能和ca

JAVA 语言如何进行异常处理,关键字: throws,throw,try,catch,finally分别代表什么意义? 在try块中可以抛 出异常吗?

Java通过面向对象的方法进行异常处理,把各种不同的异常进行分类, 并提供了良好的接口.        在 Java中,每个异常都是一个对象,它是 Throwable 类或其它子类的实例.当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并进行处理. Java的异常处理是通过 5个关键词来实现的: try. catch. throw.throws和finally.       一般情况下是用 try来执行一段程序,如果出现异常,系统会抛出( th

ArrayList迭代修改抛出ConcurrentModificationException

extends:http://www.cnblogs.com/dolphin0520/p/3933551.html Iterator<Integer> iterator = list.iterator(); while(iterator.hasNext()){ Integer integer = iterator.next(); if(integer==2) iterator.remove(); }  

ArrayList中的modCount与ConcurrentModificationException

在看ArrayList源码时,看到了一个字段modCount.在add.remove.clear等方法中都有modCount++的操作.不明白什么意思.点进去看了看该字段的解释,总算明白了.modCount是在AbstractList抽象类中定义的.该字段的解释如下所示. /** * The number of times this list has been <i>structurally modified</i>. * Structural modifications are

More Effective C++----(12)理解&quot;抛出一个异常&quot;与&quot;传递一个参数&quot;或&quot;调用一个虚函数&quot;间的差异

Item M12:理解"抛出一个异常"与"传递一个参数"或"调用一个虚函数"间的差异 从语法上看,在函数里声明参数与在catch子句中声明参数几乎没有什么差别: class Widget { ... }; //一个类,具体是什么类 // 在这里并不重要 void f1(Widget w); // 一些函数,其参数分别为 void f2(Widget& w); // Widget, Widget&,或 void f3(const W

黑马程序员——————&gt; 异常处理之抛出

------- android培训.java培训.期待与您交流! ---------- java的异常被分类为两大类,Checked异常和Runtime异常(运行时异常).所有的RuntimeException类及其子类的实例被称为Runtime异常:不是RuntimeException类及其子类的异常实例则被称为Checked异常. 对于Checked异常的处理方式有如下两种. 1:当前方法明确知道如何处理该异常,程序应该使用try...catch块来捕获该异常,然后在对应的catch块中修复

C++学习40 抛出自己的异常

throw 是C++中的关键字,用来抛出异常.如果不使用 throw 关键字,try 就什么也捕获不到:上节提到的 at() 函数在内部也使用了 throw 关键字来抛出异常. throw 既可以用在标准库中,也可以用在自定义的函数中,抛出我们期望的异常.throw 关键字语法为: throw exceptionData; exceptionData 是“异常数据”的意思,它既可以是一个普通变量,也可以是一个对象,只要能在 catch 中匹配就可以. 下面的例子演示了如何使用 throw 关键字