博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
转:集合在迭代过程中能否添加、删除或修改元素
阅读量:6597 次
发布时间:2019-06-24

本文共 3927 字,大约阅读时间需要 13 分钟。

另外补充:

获取iterator 后,如果增加或删除了元素,要重写获取iterator~ 

原因是,获取iterator时,初始化iterator会记住对应集合的元素个数,之后增加或删除了集合中的元素,那么集合送元素个数和 iterator中记录的个数就不一致了,会报错(报的错误和下文中相同,因为本质上问题根源是一样的)

 

原文地址:

 

1.使用 for 循环

1 List
list = new ArrayList<>(); 2 list.add("1"); 3 list.add("2"); 4 list.add("3"); 5 for (int i = 0; i < list.size(); i++) { 6 System.out.println(list.size()); 7 if ("1".equals(list.get(i))){ 8 list.add("4"); 9 list.remove("1");10 }11 }

2.使用 foreach 遍历

1 List
list = new ArrayList<>(); 2 list.add("1"); 3 list.add("2"); 4 list.add("3"); 5 for (String s : list){ 6 if ("1".equals(s)){ 7 list.add("4"); 8 list.remove("1"); 9 }10 }

3.使用 Iterator 迭代器

1 List
list = new ArrayList<>(); 2 list.add("1"); 3 list.add("2"); 4 list.add("3"); 5 Iterator
iterator = list.iterator(); 6 while (iterator.hasNext()) { 7 if ("1".equals(iterator.next())) { 8 iterator.remove(); 9 list.add("4");10 list.remove("1");11 }12 }

在第一种情况下编译和运行都是可以的,第二种和第三种则会抛出 java.util.ConcurrentModificationException 的异常,这是为什么呢?
下面一段是来自百度知道的解释:
逻辑上讲,迭代时可以添加元素,但是一旦开放这个功能,很有可能造成很多意想不到的情况。
比如你在迭代一个 ArrayList,迭代器的工作方式是依次返回给你第0个元素,第1个元素,等等,假设当你迭代到第5个元素的时候,你突然在ArrayList的头部插入了一个元素,使得你所有的元素都往后移动,于是你当前访问的第5个元素就会被重复访问。
java 认为在迭代过程中,容器应当保持不变。因此,java 容器中通常保留了一个域称为 modCount,每次你对容器修改,这个值就会加1。当你调用 iterator 方法时,返回的迭代器会记住当前的 modCount,随后迭代过程中会检查这个值,一旦发现这个值发生变化,就说明你对容器做了修改,就会抛异常。
我们先看第三种情况,即使用 Iterator 迭代器对集合进行遍历,我们以 AbstractList 为例。
首先来看一下AbstractList是如何创建Iterator的,AbstractList有一个内部类:

1 private class Itr implements Iterator
{2 ...3 }

而创建Iterator需要调用iterator()方法:

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

 

所以在调用集合的iterator方法之后实际上返回了一个内部类的实例。

我们看一下Itr这个类的next()方法是如何实现的:

1 public E next() { 2             checkForComodification(); 3             try { 4                 int i = cursor; 5                 E next = get(i); 6                 lastRet = i; 7                 cursor = i + 1; 8                 return next; 9             } catch (IndexOutOfBoundsException e) {10                 checkForComodification();11                 throw new NoSuchElementException();12             }13         }

 

checkForComodification()方法的实现如下:

1 final void checkForComodification() {2             if (modCount != expectedModCount)3                 throw new ConcurrentModificationException();4         }

modCount表示集合的元素被修改的次数,每次增加或删除一个元素的时候,modCount都会加一,而expectedModCount用于记录在集合遍历之前的modCount,检查这两者是否相等就是为了检查集合在迭代遍历的过程中有没有被修改,如果被修改了,就会在运行时抛出ConcurrentModificationException这个RuntimeException,以提醒开发者集合已经被修改。
这就说明了为什么集合在使用Iterator进行遍历的时候不能使用集合本身的add或者remove方法来增减元素。但是使用Iterator的remove方法是可以的,至于原因可以看一下这个方法的实现:

1 public void remove() { 2             if (lastRet < 0) 3                 throw new IllegalStateException(); 4             checkForComodification(); 5  6             try { 7                 AbstractList.this.remove(lastRet); 8                 if (lastRet < cursor) 9                     cursor--;10                 lastRet = -1;11                 expectedModCount = modCount;12             } catch (IndexOutOfBoundsException e) {13                 throw new ConcurrentModificationException();14             }15         }

 

 

可以看到,在集合的元素被remove之后,expectedModCount被重新赋值,是的modCount总是等于expectedModCount,所以不会抛出ConcurrentModificationException异常。

而上面提到的第二种使用foreach来对集合进行遍历本质上和第三种情况是一样的,因为根据Oracle提供的文档,foreach内部的实现机制其实就是使用的Iterator。

第一种使用for循环进行遍历时内部使用的就是集合本身的遍历方法,这里不做讨论。

---------------------
作者:小明的代码世界
来源:CSDN
原文:https://blog.csdn.net/cmder1000/article/details/73865815
版权声明:本文为博主原创文章,转载请附上博文链接!

转载于:https://www.cnblogs.com/mumu122GIS/p/9987949.html

你可能感兴趣的文章
JS动态生成Input文本框 并获取文本框值
查看>>
JSP出现中文乱码问题
查看>>
fuzhou 1075 分解素因子
查看>>
启明开发板测试以太网插拔网线,改造以支持网线插拔检测
查看>>
iOS 根据字符串来定位地址
查看>>
Centos清理内存 内存回收释放及内存使用查看的相关命令
查看>>
ASP.NET Core MVC之ViewComponents(视图组件)知多少?
查看>>
Wlms进程导致Windows2008R2操作系统关机的解决办法
查看>>
第一周 从C走进C++ 005 const
查看>>
cmake生成Makefile时指定c/c++编译器
查看>>
R语言进行广州租房可视化
查看>>
Asp.net WebApi 项目示例(增删改查)
查看>>
数据库系统原理第一章数据库系统的基本概念
查看>>
pyrhon SQLite数据库
查看>>
C#开源框架(转载)
查看>>
fatal error C1083: 无法打开包括文件:“stddef.h”: No such file or directory
查看>>
流于形式的沟通
查看>>
电梯问题
查看>>
python错误处理之try...except...finally...错误处理机制。
查看>>
bootstrap复选框和单选按钮
查看>>