今天一朋友问了个问题,对于如下一段代码,运行后会有怎样的结果?

public class ArrayListTest {

    public static void main(String[] args) {
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
for (Integer num : list) {
if(num == 4){
list.remove(num);
}
}
System.out.println(list);
} }

由于本人之前对于集合框架中的fail-fast机制有过一些了解,所以看到这种写法,很自然的认为会出现java.util.ConcurrentModificationException异常,控制台并不会输出预期的结果。

但事实情况呢?看如下截图,执行成功了。

本人又尝试将if判断中num依次换成1,2,3,结果和预期一样了。

到底是什么原因呢,只有删除倒数第二个元素的场景结果和预期不一样。

本人带着好奇心、调试了一把源码,终于发现了庐山真面目。

类似于以上的forEach循环,其实是一种语法糖,调试后就会发现,list在循环时是由Iterator迭代器来实现的。

所以真实的代码则类似如下:

public class ArrayListTest {

    public static void main(String[] args) {
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
for (Iterator<Integer> itr = list.iterator(); itr.hasNext();){
int num = itr.next();
if(num == 4){
list.remove(num);
}
}
System.out.println(list);
} }

调试后终于发现了玄机,先看下面三个迭代器的关键属性:

cursor --迭代器的游标,元素的索引值,初始值为0

lastRet --返回最后一个元素的索引值、如果没有找到则返回-1

expectedModCount --修改次数的期望值,可以看到在迭代器初始化时,这个属性就被赋值为当前修改次数的值了。

checkForComodification --此方法用来检查修改次数是否发生变化,从而判断是否需要触发fail-fast异常。

在迭代过程中,每一次迭代,cursor会+1, 而itr.hasNext()会判断是否存在下一个元素、irt.next()获取下一个元素的值,最终直到不存在下一个元素,则迭代结束。

跟进源码发现,itr.hasNext()判断方法并不会调用checkForComodification方法来检查list在迭代中是否有被修改,只是判断游标和长度是否相等,不等时则认为存在下一个元素。

在删除倒数第二个元素的场景下:当倒数第二个元素时迭代完成,开始迭代最后一个元素时,此时cursor是4,size由于在迭代过程倒数第二个元素移除了,所以-1, 此时cursor和size相等,不会再进入下一个迭代,因此不会触发checkForComodification方法的fail-fast机制。

其他三种情况,再删除元素后的下一个迭代,由于会调用it.next()方法,则会触发ConcurrentModificationException异常。

通过这次对arraylist中iterator迭代器源码的深入学习,本人对于迭代器的运作机制又有了进一步的认知。后续还要再深入学习jdk中的集合框架源码,不能过于自信~

ArrayList之foreach循环删除倒数第二个元素,不触发fail-fast机制的更多相关文章

  1. ArrayList在foreach删除倒数第二个元素不抛并发修改异常的问题

    平时我们使用ArrayList比较多,但是我们是否知道ArrayList在进行foreach的时候不能直接通过list的add或者move方法进行删除呢, 原因就是在我们进行foreach遍历的时候, ...

  2. 关于java中ArrayList的快速失败机制的漏洞——使用迭代器循环时删除倒数第二个元素不会报错

    一.问题描述 话不多说,先上代码: public static void main(String[] args) throws InterruptedException { List<Strin ...

  3. Java循环删除集合多个元素的正确打开方式

    首先说下不正确的打开方式: 第一:使用for循环删除集合的元素,示例代码如下 ArrayList<String> list = new ArrayList<String>(Ar ...

  4. foreach循环里不能remove/add元素的原理

    foreach循环 ​    foreach循环(Foreach loop)是计算机编程语言中的一种控制流程语句,通常用来循环遍历数组或集合中的元素.Java语言从JDK 1.5.0开始引入forea ...

  5. 集合赋值及for循环删除符合条件的元素

    一.Java语言中ArrayList对象能直接赋值给另一个ArrayList对象吗? https://zhidao.baidu.com/question/399214655.html ArrayLis ...

  6. Python笔记:用for循环删除列表中的元素

    for运行过程中会有一个指针来记录当前循环的元素是哪一个,一开始这个指针指向第0个元素,然后获取它,接着删除第0个元素,这时候,原来是第1个的元素会变成第0个,当指针向后移动一次,指向了现在第1个元素 ...

  7. (CSDN 迁移) JAVA循环删除List的某个元素

    若列表中只可能存在一个则可以用简单的循环删除,不多说. 若列表中可能存在多个,尤其是可能有多个连续的需要删除,用简单循环有可能发生异常. 需要使用迭代器(Iterator),两种具体实现: 逻辑上是一 ...

  8. 循环删除List集合的元素

    之前在使用list集合循环删除元素的时候,竟然出现了集合内的元素不能删除成功的问题,之后整理了一下,发现大有玄机! 1.如果指定了list的size大小,会出现下标越界异常 List<Strin ...

  9. python循环删除list中的元素

    直接上例子: a = [1,2,3,4,5,6] for i in a: a.remove(i) print(a) 返回:[2, 4, 6] 循环a,想删除a的所有元素,但实际确有数据保留了下来,这是 ...

随机推荐

  1. CentOS8安装docker

    参考:https://www.cnblogs.com/ding2016/p/11592999.html 一,安装环境查看 二,下载docker-ce的repo curl https://downloa ...

  2. Mathtype安装与最简破解

    1.MathType资源 链接: https://pan.baidu.com/s/1UapJCcfU7Me_rIWdAe5nfw   提取码:   1y9i 2.破解 我之前的30天试用期过了,没来得 ...

  3. 个人博客搭建全记录(Hexo,Github)

    搭建过程主要借鉴小歪的博客 博客主题airclod Hexo,Github建站记录 1. 准备 Github账号 注册登陆Github 创建Repository,Repository Name就是Yo ...

  4. Andrew Ng机器学习课程9

    Andrew Ng机器学习课程9 首先以一个工匠为例,说明要成为一个出色的工匠,就需要掌握各种工具的使用,才能知道在具体的任务中选择什么工具来做.所以今天要讲的就是机器学习的理论部分. bias va ...

  5. JIRA中的并联审批流程定制

    JIRA号称可以跟踪任何事务,让JIRA的流程来匹配团队的工作流程,而不是让你的团队适应JIRA的工作流程.但是在实践中,有些有些流程用JIRA还是比较困难的,比如并联审批流程,一个并联审批流程需求大 ...

  6. 浅谈python反序列化漏洞

    最近看到p神一篇讲python反序列化的文章,结合redis未授权访问组合漏洞,感觉在flask和redis的构架中比较常见,便记录下来. p神原文:https://www.leavesongs.co ...

  7. Ribbon学习笔记

    微服务的概念: Ribbon默认的是轮询的算法:   @LoadBalanced @EnableEurekaClient Irule是根据 Ribbon默认(轮询)的7中负载均衡的算法: 修改默认的R ...

  8. LeetCode 718. 最长重复子数组(Maximum Length of Repeated Subarray)

    718. 最长重复子数组 718. Maximum Length of Repeated Subarray 题目描述 给定一个含有 n 个正整数的数组和一个正整数 s,找出该数组中满足其和 ≥ s 的 ...

  9. pytorch1.0批训练神经网络

    pytorch1.0批训练神经网络 import torch import torch.utils.data as Data # Torch 中提供了一种帮助整理数据结构的工具, 叫做 DataLoa ...

  10. Linux基础-10-网络原理和基础设置

    1. 使用ifconfig命令来维护网络 1) ifconfig命令的功能:显示所有正在启动的网卡的详细信息或设定系统中网卡的IP地址. 2) 应用ifconfig命令设定网卡的IP地址: 例如:修改 ...