千锋教育-做有情怀、有良心、有品质的职业教育机构

400-811-9990
手机站
千锋教育

千锋学习站 | 随时随地免费学

千锋教育

扫一扫进入千锋手机站

领取全套视频
千锋教育

关注千锋学习站小程序
随时随地免费学习课程

上海
  • 北京
  • 郑州
  • 武汉
  • 成都
  • 西安
  • 沈阳
  • 广州
  • 南京
  • 深圳
  • 大连
  • 青岛
  • 杭州
  • 重庆
当前位置:重庆千锋IT培训  >  技术干货  >  Iterator接口使用时并发修改异常的解决过程

Iterator接口使用时并发修改异常的解决过程

来源:千锋教育
发布人:lxl
时间: 2023-05-06 11:19:16

  相信很多小伙伴通过对JavaSE基础内容的学习,已经对List集合有了较好的掌握,那接着就请大家跟着来回顾一下List相关的内容吧。大家知道,我们在遍历List集合时,通常会使用Iterator接口来迭代集合中的元素。但是,如果我们对Iterator接口使用不当,就可能会导致并发修改异常,即java.util.ArrayList$Itr.checkForComodification异常。那这个checkForComodification异常到底是如何产生的呢?接下来就请大家来跟随袁老师的步伐,一点点揭开它的神秘面纱吧。

  一. 什么是异常

  首先,简单带大家回顾一下异常的相关知识。我们举个例子好,就好比人人都希望自己身体健康,遇到的事情都能顺利解决,但在实际生活中总会遇到各种状况,比如感冒发烧,工作时电脑蓝屏、死机等。

  同样,在程序运行的过程中,也会发生各种非正常的状况。例如,程序运行时磁盘空间不足、网络连接中断、被装载的类不存在等。针对这种情况, Java语言给我们引入了异常处理机制,以异常类的形式对这些非正常情况进行封装,利用异常处理机制对程序运行时发生的各种问题进行处理。

  接下来我们通过一个案例来认识一下什么是异常。

public class Example01 {
public static void main(String[] args) {
int result = divide(4, 0); // 调用divide()方法
System.out.println(result);
}
// 下面的方法实现了两个整数相除
public static int divide(int x, int y) {
int result = x / y; // 定义一个变量result记录两个数相除的结果
return result; // 将结果返回
}
}

   上述代码的运行结果如下图所示:

Iterator接口使用时并发修改异常的解决过程

  从运行结果可以看出,这个程序发生了算术异常(ArithmeticException),该异常是由于调用divide()方法时传入了参数0,运算时出现了被0除的情况。该异常发生后,程序就会立即结束,无法继续向下执行。

  二. Iterator接口

  我们在程序开发中,经常需要遍历集合中的所有元素。针对这种需求,Java专门提供了一个Iterator接口。Iterator接口也是集合中的一员,但它与Collection、Map接口有所不同。Collection接口与Map接口主要用于存储元素,而Iterator则主要用于迭代访问(即遍历)Collection中的元素,因此Iterator对象也被称为迭代器。

  接下来我们再通过一个案例,来学习如何使用Iterator迭代集合中的元素。

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

public class Example02 {
public static void main(String[] args) {
ArrayList list = new ArrayList(); // 创建ArrayList集合
list.add("张三"); // 向该集合中添加字符串
list.add("李四");
list.add("王五");
list.add("赵六");
Iterator it = list.iterator(); // 获取Iterator对象
while (it.hasNext()) { // 判断ArrayList集合中是否存在下一个元素
Object obj = it.next(); // 取出ArrayList集合中的元素
System.out.println(obj);
}
}
}

   当遍历元素时,首先通过调用ArrayList集合的iterator()方法来获得迭代器对象;然后使用hasNext()方法判断集合中是否存在下一个元素。如果存在,则调用next()方法将元素取出,否则说明已到达了集合末尾,停止遍历元素。需要注意的是,在通过next()方法获取元素时,我们必须保证要获取的元素存在,否则,就会抛出NoSuchElementException异常。

  Iterator迭代器在遍历集合时,内部采用指针的方式来跟踪集合中的元素,为了让初学者更好地理解迭代器的工作原理,接下来袁老师再通过一个图例来演示Iterator对象迭代元素的过程。

Iterator接口使用时并发修改异常的解决过程

  上图中,我们在调用Iterator的next()方法之前,迭代器的索引位于第一个元素之前,不指向任何元素。当第一次调用迭代器的next()方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回。当再次调用next()方法时,迭代器的索引会指向第二个元素并将该元素返回。然后以此类推,直到hasNext()方法返回false,表示到达了集合的末尾,终止对元素的遍历。

  通过迭代器获取ArrayList集合中的元素时,这些元素的类型都是Object类型。如果我们想获取到特定类型的元素,则需要进行对数据类型强制转换。

  通过对上述案例的分析,想必各位小伙伴对如何使用Iterator接口来迭代集合中的元素,已经掌握的很深入了。那么如果我们在使用Iterator迭代集合元素时,如果使用不当就可能会产生并发修改的异常,下面就再请大家来跟随袁老师的思路,咱们一块儿来探索这个问题。

  三. 并发修改异常

  在使用Iterator迭代器对集合中的元素进行迭代时,如果我们调用了集合对象的remove()方法去删除元素之后,继续使用迭代器遍历元素,就会出现异常。

  下面我们通过一个案例来演示这种异常。假设在一个集合中存储了学校里所有学生的姓名,由于一个名为“张三”的学生中途转学,这时就需要在迭代集合时找出该元素并将其删除,具体代码如下。

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

public class Example03 {
public static void main(String[] args) {
ArrayList list = new ArrayList(); // 创建ArrayList集合
list.add("张三");
list.add("李四");
list.add("王五");
Iterator it = list.iterator(); // 获得Iterator对象
while (it.hasNext()) { // 判断该集合是否有下一个元素
Object obj = it.next(); // 获取该集合中的元素
if ("张三".equals(obj)) { // 判断该集合中的元素是否为张三
list.remove(obj); // 删除该集合中的元素
}
}
System.out.println(list);
}
}

   上述程序在运行时出现了并发修改异常ConcurrentModificationException,这个异常是由迭代器对象抛出的。而出现该异常的原因是集合在迭代器运行期间删除了元素,这会导致迭代器预期的迭代次数发生改变,导致迭代器的结果不准确。

图片3

  要解决上述问题,我们可以采用两种方式,下面袁老师会对这两种方式分别进行介绍。

  第一种方式:从业务逻辑上讲,我们只想将姓名为“张三”的学生删除,至于后面还有多少学生并不关心。所以我们只需找到该学生跳出循环不再迭代即可,也就是可以在第12行代码下面增加一个break语句,代码如下:

if ("张三".equals(obj)) {
list.remove(obj);
break;
}

   第二种方式:如果我们需要在迭代集合期间对集合中的元素进行删除,可以使用迭代器本身的删除方法,将第12行代码替换成it.remove()方法,即可解决这个问题:

if ("张三".equals(obj)) {
it.remove();
}

   由运行结果可知,学员“张三”确实被删除了,且没有出现异常。因此我们可以得出结论,当调用迭代器对象的remove()方法来删除元素,会导致迭代次数的变化,这对于迭代器对象本身来讲是可预知的。

声明:本站稿件版权均属千锋教育所有,未经许可不得擅自转载。

猜你喜欢LIKE

如何进行mysql数据备份?

2023-05-30

从零开始学Java之Java中的内部类是怎么回事?

2023-05-29

什么是事件流以及事件流的传播机制 ?

2023-05-29

最新文章NEW

什么是servlet的生命周期?servlet请求处理流程是怎样的?

2023-05-30

在java中,super关键字怎样使用

2023-05-29

什么是JavaScript伪数组?

2023-05-25

相关推荐HOT

更多>>

快速通道 更多>>

最新开班信息 更多>>

网友热搜 更多>>