mysql for 循环删除_Java增强for循环中删除元素抛异常问题
前言
- 最近突然想起刚毕业那会找工作时面试被问了个这样的问题。就是“使用增强for循环遍历ArrayList(List集合)时删除其中的元素是否会出现异常?”。说实话当时真把我愣住了,我当时的回答是:ArrayList内部使用的是Object数组,所以在增删时会自动挪动下标,而且对于数组而言长度是固定的,没有元素的位置会用null填充,虽然我没试过但我觉得不会抛异常。
- 现在想起这件事自己都觉得有些搞笑,哈哈,经验少也是没办法。现在回想既然面试官问得出这样的问题肯定是会抛出异常的,这个拿大腿都能想到,但是为什么呢?今天就这个问题来分析一下源码到底是怎么一回事。
- 文章分为两部分。首先是了解迭代器设计模式,然后再拿ArrayList作为例子进行源码分析。
迭代器模式
用途
- 遍历集合中的元素
- 优点是无序暴露集合内部信息,且迭代器可以为不同结构集合指定统一接口
- 缺点是每一个迭代器实现只对应一个特定结构的集合,也就是说如果集合类型繁多就增加迭代器的实现的个数
自定义迭代器
- 迭代器模式其实也很简单,主要角色有:自定义集合、迭代器接口、迭代器实现3个
- 以下例子并不严谨,只作为了解迭代器的参考
自定义集合
以数组作为内部存储结构(模仿ArrayList)
迭代器接口
迭代器实现
小结
- 迭代器的本质就是用来遍历某个时间点集合中的元素
- 在上面的例子中,MyListIterator 相当于在 MyList.iterator() 时copy了一份 MyList 的元素然后进行遍历
- 结合上面这个简单的例子可以得出结论,在迭代器迭代元素过程中,源集合序列是否允许被修改。上面例子我并没有做任何处理,所以在迭代器迭代元素过程中源集合序列是可以被修改。但这样就存在问题了,就是并发操作时迭代的元素序列可能会与源集合序列不一致。那为什么要引出这个问题呢?这是为了响应文章开头讨论的问题。即为什么增强for循环遍历List集合时删除元素会抛出异常,原因有以下两个:增强for循环使用迭代器实现(可以通过Debug观察)在JDK中集合的迭代器实现是不允许在迭代元素过程中源集合序列被修改的,即为了保证迭代元素序列和源元素序列的一致性。
ArrayList迭代器浅析
异常问题
可以看到在增强for循环遍历过程中如果删除一个元素会抛出 ConcurrentModificationException 。该异常的用意是并发修改是不允许的(说明源自 ConcurrentModificationException 类注释)。从异常中可以看到问题出自 ArrayList$Itr.next 方法,该方法中触发了 ArrayList$Itr.checkForComodification 导致了异常的发生
ArrayList$Itr (迭代器实现)源码
可以在源码中看到 next 方法中会先触发 checkForComodification 来检测源集合序列是否被修改,没有被修改才会继续操作,否则抛出异常。但我们想深一层,next 和 checkForComodification 两个方法其实都不是线程安全的,因此在多线程并发过程中并不能保证一致性。那么为什么需要 checkForComodification 呢?或者问 checkForComodification 的意义何在?其实这种操常被人叫做 fail-fast 机制,即快速失败。大概的用意是,如果不满足条件就没必要继续执行了,这时可以是跳过操作(比如continue和break),或者是抛出异常等等。这操作好比如我们在执行逻辑前会先判断传入的参数是否为null,如果为null则抛异常,道理是一样的。
增强for循环中删除元素是不是一定抛异常?
- 答案是否定的。原因是增强for循环本质是 Iterator 。而 Iterator 的操作步骤是先 hasNext 判断有没有下一个元素(判断的依据是源集合的size变量)。然后如果 hasNext 返回 true 才可以进行 next 操作。
- 所以什么情况下在增强for循环中删除元素不会抛出 ConcurrentModificationException 异常呢?答案就是,删除元素后(导致源集合序列的size减1)hasNext 正好返回false就不会抛出异常(删除的元素正好是倒数第2个)。因为返回false就不会触发 next 方法的 checkForComodification 操作。
- 例子如下:
喜欢的话点点关注~~~
头条号作者:帧言
mysql for 循环删除_Java增强for循环中删除元素抛异常问题相关推荐
- java map遍历删除_Java Map在遍历过程中删除元素
map遍历判断筛选删除时 如果对map使用put.remove或clear方法(例如map.remove直接删除),那么迭代器就不再合法(并且在其后使用该迭代器将会有ConcurrentModific ...
- java 增强for循环 i_java入门 -- 增强for循环
import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; ...
- cte公用表表达式_CTE SQL删除; 在SQL Server中删除具有公用表表达式的数据时的注意事项
cte公用表表达式 In this article, the latest in our series on Common table expressions, we'll review CTE SQ ...
- java 循环写法_java的for循环的几种写法
J2SE 1.5提供了另一种形式的for循环.借助这种形式的for循环,可以用更简单地方式来遍历数组和Collection等类型的对象.本文介绍使用这种循环的具体方式,说明如何自行定义能被这样遍历的类 ...
- java双重for循环流程图_java 流程执行 循环 foreach循环
一. if分支 1. 结构 if else if else 2.执行原则 if if if 结构 会一直去执行()里的判断语句 if else if else if 结构 只要一条( ...
- java双重for循环流程图_Java的for循环
Java有好几种循环语句. for循环是Java的循环之一. for循环在java中用于重复执行一些语句,直到条件返回false. for循环有以下三个部分. 初始化 循环条件 自增或自减 for循环 ...
- Swift for循环:用于索引,数组中的元素?
本文翻译自:Swift for loop: for index, element in array? Is there a function that I can use to iterate ove ...
- Java 集合中遍历删除元素抛异常的原因,从ArrayList说起
文章目录 使用for删除遗漏元素的原因: 使用foreach删除报错的原因: 其它集合的删除方法 删除集合元素的工具类 ArrayList删除元素的方式. 使用for循环删除.会遗漏删除的元素 使用f ...
- java类怎么删除对象_在java中删除一个对象?
在java中删除一个对象? 我想删除一个我创build的对象(跟随着你的一个椭圆),但是我怎么做呢? delete follower1; 没有工作. 编辑: 好吧,我会给更多的上下文. 我正在制作一个 ...
最新文章
- 伪指令 .align 的含义
- 最新增值税商品税目编码表_大家好!我叫增值税!这是我的最新最全税率表
- 写给准备找工作的同志们!!!!(转载)
- 数组的定义格式三_省略的静态初始化
- 如何使用Photoshop制作真实的尺子
- php 后退按钮事件,php – 后退按钮的会话问题
- redis集群linux安装教程,linux下redis集群的原生安装方式部署
- (十八)密度聚类DBSCAN
- 并查集(2)-按秩合并和路径压缩
- .Net 并发写入文件的多种方式
- Python对话框使用
- shotcut添加字幕
- 未知usb设备(设备描述请求失败)_USB 之传输事务
- 74HC238引脚定义 使用方法
- audio标签的播放、暂停、重播、进度拖拽等操作
- SOA面向服务体系的架构
- linux 进程迁移,记一次成功的 linux 系统迁移
- Transformer(“变形金刚”)
- 特别有趣的猜数小游戏
- persevere的用法_persevere是什么意思_persevere的翻译_音标_读音_用法_例句_爱词霸在线词典...
热门文章
- 发外链网站服务器瘫痪,哪些操作可以导致网站接入瘫痪 - 搜外SEO问答
- php 数据映射,数据映射模式(Data Mapper)
- Java中提取字符串中的数字
- php日历排班表,日历排班表软件下载
- 【数据结构与算法】算法的空间复杂度
- 使用MyEclipse开发中的编码设置
- arch Linux添加源,在Arch Linux系统中使用Archlinuxcn源(清华源)的方法
- 充电枪cp信号控制板_筋膜枪究竟是不是智商税?评测后,我的回答更坚定了
- 职友集 进化者机器人_麦克风解决方案将发掘交互式机器人的无限潜力
- sqlplus可以连接plsql连接不上_Gee引擎配置微端不更新,连接不上,尝试重新连接的解决方法...