在使用Iterator来迭代遍历List的时候如果修改该List对象,则会报java.util.ConcurrentModificationException异常,下面看一个例子演示:

 1 package com.others;
 2
 3 import java.util.ArrayList;
 4 import java.util.Iterator;
 5 import java.util.List;
 6 import java.util.concurrent.CopyOnWriteArrayList;
 7
 8 public class ArrayListTest {
 9
10     public static void main(String[] args) {
11         List<String> list = new ArrayList<String>();
12         //CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
13         list.add("a");
14         list.add("b");
15         list.add("c");
16         list.add("d");
17         list.add("e");
18         Iterator iterator = list.iterator();
19         while(iterator.hasNext()){
20             String str = (String) iterator.next();
21             if(str.equals("c")){
22                 list.remove(str);
23             }else{
24                 System.out.println(str);
25             }
26         }
27     }
28
29 }

  结果为:

a
b
Exception in thread "main" java.util.ConcurrentModificationExceptionat java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)at java.util.ArrayList$Itr.next(ArrayList.java:791)at com.others.ArrayListTest.main(ArrayListTest.java:20)

  当调用list的iterator()方法的时候,返回的是一个Itr对象(实现了Iterator接口):

1 public Iterator<E> iterator() {
2         return new Itr();
3     }

  我们看一下Itr这个类:

 1 private class Itr implements Iterator<E> {
 2         int cursor;       // index of next element to return
 3         int lastRet = -1; // index of last element returned; -1 if no such
 4         int expectedModCount = modCount; //刚创建迭代对象的时候List的modCount
 5
 6         public boolean hasNext() {
 7             return cursor != size;
 8         }
 9
10         @SuppressWarnings("unchecked")
11         public E next() {
12             checkForComodification(); //每调用一次next()函数都会调用checkForComodification方法判断一次
13             int i = cursor;
14             if (i >= size)
15                 throw new NoSuchElementException();
16             Object[] elementData = ArrayList.this.elementData;
17             if (i >= elementData.length)
18                 throw new ConcurrentModificationException();
19             cursor = i + 1;
20             return (E) elementData[lastRet = i];
21         }
22
23         public void remove() {
24             if (lastRet < 0)
25                 throw new IllegalStateException();
26             checkForComodification();
27
28             try {
29                 ArrayList.this.remove(lastRet);
30                 cursor = lastRet;
31                 lastRet = -1;
32                 expectedModCount = modCount;
33             } catch (IndexOutOfBoundsException ex) {
34                 throw new ConcurrentModificationException();
35             }
36         }
37         //此方法用来判断创建迭代对象的时候List的modCount与现在List的modCount是否一样,不一样的话就报ConcurrentModificationException异常
38         final void checkForComodification() {
39             if (modCount != expectedModCount)
40                 throw new ConcurrentModificationException();
41         }
42     }

  List对象有一个成员变量modCount,它代表该List对象被修改的次数,每对List对象修改一次,modCount都会加1.

  Itr类里有一个成员变量expectedModCount,它的值为创建Itr对象的时候List的modCount值。用此变量来检验在迭代过程中List对象是否被修改了,如果被修改了则抛出java.util.ConcurrentModificationException异常。在每次调用Itr对象的next()方法的时候都会调用checkForComodification()方法进行一次检验,checkForComodification()方法中做的工作就是比较expectedModCount 和modCount的值是否相等,如果不相等,就认为还有其他对象正在对当前的List进行操作,那个就会抛出ConcurrentModificationException异常。

  我们再来分析一下上面那个例子,当例子程序执行到22行的时候,将list对象里面的“c"删除了,同时list对象的modCount值加1,但是Itr对象的expectedModCount没有变,他们肯定是不相等了。等再一次执行next()方法的时候调用了checkForComodification()方法,这时候就抛出异常了。

  我们再将上面那个例子稍微改动一下:将21行改为if(str.equals("d")){,即删除”d"这个元素。运行结果如下:

a

b

c

  这时却没有报异常了,但是“e"却没有输出来,这是为什么呢?原因很简单,我们看到Itr的hashNext()方法:

1 public boolean hasNext() {
2             return cursor != size;
3         }

  它是通过Itr的对象的cursor与List对象的size值来判断是否还有未迭代的对象,当遍历完“d"的时候cursor=4,删除”d"的时候,List对象的size就会减1,size首先为5,后来变为4,这时候cursor和size是相等的,hasNext()方法返回的是false,就认为遍历结束了,所以删除以后没有进去执行next()方法了,就没有抛出异常了,当然"e"也没有输出来。

  为了避免这种异常,我们可以使用CopyOnWriteArrayList来代替ArrayList,CopyOnWriteArrayList支持并发访问,所以同时进行迭代和修改是没有问题的。

使用迭代器遍历List的时候修改List报ConcurrentModificationException异常原因分析相关推荐

  1. Java遍历List和Map出现ConcurrentModificationException异常原因分析及解决方法

    Java遍历 List 和 Map 出现 ConcurrentModificationException 异常原因分析及解决方法 一.单线程 异常情况举例 只要抛出出现异常,可以肯定的是代码一定有错误 ...

  2. lamuda表达式 list移除空元素_java8 Lambda表达式遍历并移除元素,报错:ConcurrentModificationException的解决办法...

    1.情景展示 已知json对象MainExt 需要把值为空数组的key移除掉,下面是执行代码 执行结果报错:java.util.ConcurrentModificationException 2.原因 ...

  3. 循环遍历和迭代器遍历如何选择

    对于数据的遍历,常见的操作方式有两种:循环遍历和迭代器遍历.有时候,我们容易混淆这两种遍历方式,误以为这两种方式并没有根本就没有什么大的区别. 1.定义 (1)循环遍历:一般而言,我们常见的while ...

  4. 容器删除元素后迭代器失效_使用迭代器遍历容器元素

    迭代器为我们提供了统一的遍历容器的方式. 1.Iterator源码分析 public Iterator<E> iterator() {return new Itr(); }private ...

  5. 定义一个学生类Student,包含三个属性姓名、年龄、性别, 创建三个学生对象存入ArrayList集合中。 A:使用迭代器遍历集合。 B:求出年龄最大的学生,然后将该对象的姓名变为:小猪佩奇。

    Java基础 定义一个学生类Student,包含三个属性姓名.年龄.性别, 创建三个学生对象存入ArrayList集合中. A:使用迭代器遍历集合. B:求出年龄最大的学生,然后将该对象的姓名变为:小 ...

  6. Java遍历集合元素并修改

    结论:fori循环可以修改.删除.添加,但是要注意的是下标还是元素:增强for循环内,可以修改,不可以删除.添加.想要删除.添加,使用集合迭代器的删除.添加方法. 对List和Set的遍历,有四种方式 ...

  7. 迭代器遍历,增强for遍历

    目录 一.迭代器遍历 二.增强for遍历 三.Lambda表达式遍历 一.迭代器遍历 迭代器遍历:迭代器在Java中的类是Ilterator,迭代器是集合专用的遍历方式: 创建指针,判断是否有元素,获 ...

  8. 通过foreach遍历ArrayList时同时修改报错分析

    遍历ArrayList可以有for循环.foreach.迭代器iterator.listIterator,其中通过foreach来遍历同时修改 ArrayList时会抛出 ConcurrentModi ...

  9. 使用迭代器 遍历ArrayList,遍历 Map

    通常情况下,你会希望遍历一个集合中的元素.例如,显示集合中的每个元素. 一般遍历数组都是采用for循环或者增强for,这两个方法也可以用在集合框架,但是还有一种方法是采用迭代器遍历集合框架,它是一个对 ...

最新文章

  1. 从60多场技术面试中,我总结了这份面试经验
  2. 程序员面试题精选100题(10)-排序数组中和为给定值的两个数字[算法]
  3. JDK1.8新特性:Stream流
  4. 网站bin目录下的不可以放配置文件或其他可写文件
  5. python基础入门(6)之列表
  6. Java常用接口与类——基本数据类型的包装类
  7. 有个地方叫做成都,有些菜叫川菜
  8. python怎么矩阵的秩_python – 从numpy或matlab中的满秩非矩形矩阵中获取可逆方阵...
  9. 【收藏】来电显示Modem
  10. 腾讯云API弹性公网IP踩坑
  11. 51Talk-Level 7 Unit 1 L3
  12. Burg法求解AR(p)模型参数(一)自回归模型
  13. 神奇的H5视频画中画功能
  14. mysql试题百度云_MYSQL练习题及答案
  15. utf8和utf-8 bom
  16. ios系统删除的短信如何恢复?
  17. android 服务自动运行怎么办,怎么解决安卓软件服务停止后又自启?
  18. 用 Flutter 实现 PageView 指示器
  19. 深度篇——目标检测史(八) 细说 CornerNet-Lite 目标检测
  20. (转)tomcat与地址栏图标之研究(多浏览器)

热门文章

  1. util类中非静态方法中注入serivce,在controller层是使用util。
  2. android Json详解
  3. 《JAVA与模式》之模板模式(转载)
  4. iOS 数据持久化 -- Core Data (2)
  5. Understanding Global Unicast IPv6 Addressing
  6. VS2008正式版创建silverlight项目失败的解决办法
  7. 满屋研选获1亿元B轮融资,华创资本领投,五岳资本、金地集团、治平资本等跟投...
  8. 【译Py】数据科学面试终极指南(二)
  9. HBuilder离线打包启用Chrome Inspect调试
  10. Android 图片的帧动画