java foreach 跳过本次循环_【Java】对foreach循环的思考

阿里java开发手册已经发表,很多都值得认真研究思考,看到零度的思考题,没忍住研究了一下。

de69ddf8413f2d4484cbc572f7770424.png


在这里插入图片描述

首先,看一下给出的反例的执行结果。

  1. 如果是"1",最后list中的元素为["2"]
  2. 如果把"1"换成"2",会抛出ConcurrentModificationException异常
    为什么会出现这种情况?这就要考察foreach的执行过程了。

1. 代码编译
foreach其实是一种语法糖,通过简单明了的java语法,实现相对复杂的功能,通过查看代码编译之后的字节码文件,可以看到,foreach的循环会在编译期被转为迭代器(Iterator)的方式,以下是反编译之后的代码

List<String> list = Lists.newArrayList();
list.add("1");
list.add("2");
Iterator var2 = list.iterator();
while(var2.hasNext()) {String num = (String)var2.next();if("2".equals(num)) {list.remove(num);}
}//加入Java开发交流君样:756584822一起吹水聊天

2. ArrayList中的Iterator考察

在ArrayList内部有一个Itr的内部类,该内部类实现了Iterator接口,通过ArrayList的iterator()函数获取到的就是内部类Itr的实例对象。

内部类Itr的属性说明
cursor:下一个返回元素的索引
lastRet:上一个返回元素的索引,如果没有,就是默认值-1
expectedModCount:默认值是modCount(是AbstractList的属性,表示集合结构发生变化的次数,每次add或remove都会加1),从变量定义上就可以看出它是一个期望值,用于在遍历的过程中查看ArrayList的结构有没有发生变化,有点类似CAS的做法
内部类Itr的主要函数说明

hasNext()函数

用于判断是否遍历到了集合的末尾
return cursor != size;

checkForComodification()函数

在next()和remove()函数中都会首先调用该方法来判断集合的结构是否发生变化,如果结构发生了变化,modCount就会加1,不等于expectedModCount,就会抛出异常
if (modCount != expectedModCount)
throw new ConcurrentModificationException();

next()函数

  1. 先检查集合的结构有没有发生变化,若是,则抛出异常
  2. 判断cursor有没有超过集合元素的个数
  3. 判断cursor有没有超过ArrayList底层数组结构的大小,若是,则抛出异常
  4. cursor加1,lastRet设置为当前返回元素的索引
checkForComodification();
int i = cursor;
if (i >= size)throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
//加入Java开发交流君样:756584822一起吹水聊天

remove()函数

  1. lastRet判断是否小于0,若是,表示还未开始遍历集合,迭代器当前的索引位于集合第一个元素之前
  2. 判断元素的结构有没有发生变化
  3. 通过ArrayList的remove函数去除lastRet索引位置的元素,此时modCount加1
  4. cursor回退到lastRet的索引位置,lastRet设为-1,expectedModCount设置为当前modCount值
if (lastRet < 0)throw new IllegalStateException();
checkForComodification();
try {ArrayList.this.remove(lastRet);cursor = lastRet;lastRet = -1;expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();
}//加入Java开发交流君样:756584822一起吹水聊天
  1. 结合代码分析反例

条件为"1".equals(num)的情况
第一次循环,使得cursor为1,此时,符合判断条件,调用集合的remove函数删除元素,modCount加1,此时不等于expectedModCount,size减1变为1
第二次循环,调用hasNext函数,此时cursor和size都为1,判断集合中没有可遍历的元素,遍历到了末尾,结束循环,集合中为"2"的元素是没有遍历到的
最终打印出集合,结果显示为["2"]

条件为"2".equals(num)的情况

  • 第一次循环,使得cursor为1,此时,不符合判断条件
  • 第二次循环,hasNext调用后发现集合中还有元素,继续遍历,cursor为2,此时,符合判断条件,调用集合的remove函数删除元素,modCount加1,此时expectedModCount,size减1变为1
  • 第三次循环,hasNext函数调用的时候,cursor为2,大于size,两者也不相等,返回true,继续执行循环体,此时,会调用next函数,由于next函数首先会判断集合的结构有没有发生变化,因为第二次循环中,集合的结构已经变化了,因此会抛出
    ConcurrentModificationException异常

4. 为什么正例就不会出现这种问题

因为删除元素调用的是迭代器的remove函数,size变化的同时,cursor也发生了变化,不会出现cursor大于size的情况,同时,集合结构发生变化之后,迭代器的remove函数中对expectedModCount重新设值,感知到了结构的变化

最后,并发操作,需要对迭代器加锁,就不在此赘述了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/295546.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

地球上这10个奇幻景观,带你踏入外太空

全世界只有3.14 % 的人关注了爆炸吧知识大蓝洞大蓝洞是灯塔礁的一部分&#xff0c;位于洪都拉斯伯利兹城陆地大约100公里之遥&#xff0c;是一个较大的完美环状海洋深洞&#xff0c;是当今世界最吸引人的潜水地点之一。305米的口径&#xff0c;123米的洞深&#xff0c;洞口呈现…

OSChina 周六乱弹 —— 有人骂你神经病怎么办?

2019独角兽企业重金招聘Python工程师标准>>> 周六了&#xff0c;大家有没有在认真加班呢&#xff1f;其实咱们程序员的生活真的不容易 熊大信了熊二的话&#xff1a;程序员的人生 码代码不容易&#xff0c;咱们还是去抢银行吧 sunny_chan&#xff1a;一天老师让同学…

手把手教你学Dapr - 6. 发布订阅

介绍发布/订阅模式允许微服务使用消息相互通信。生产者或发布者在不知道哪个应用程序将接收它们的情况下向主题发送消息。这涉及将它们写入输入通道。同样&#xff0c;消费者或订阅者订阅该主题并接收其消息&#xff0c;而不知道是什么服务产生了这些消息。这涉及从输出通道接收…

直男的浪漫有多可怕?

1 你不说估计没人知道&#xff08;via.信箱说i&#xff09;▼2 举报&#xff0c;此处有个疑似小偷的人&#xff01;&#xff08;via&#xff1a;不知姓名的C&#xff09;▼3 世界上最互相信任的人了吧&#xff1f;▼4 你看我这个垫肩是不是很不错&#xff01;&#xff08;素…

WPF 透明窗口在桌面上放虫子。。。

抖音上偶然看到这个&#xff0c;咱也想来一个&#xff0c;看看效果&#xff1a;实现很简单&#xff0c;一个透明窗口&#xff0c;一个gif图片&#xff0c;不显示任务栏&#xff0c;再加上鼠标穿透&#xff0c;就ok了了看看代码&#xff1a;Mainwindow.xaml:<Window x:Class&…

“凡尔赛文学”疯狂刷屏!数学家们也拼命“装”了起来,哈哈哈哈哈

全世界只有3.14 % 的人关注了爆炸吧知识凡尔赛文学与数学结合起来完美无缺大家好&#xff0c;超模君昨天在写稿时&#xff0c;表妹过来告诉我&#xff1a;“表哥你的科普文章都out了&#xff01;现在凡尔赛文学才是主流&#xff01;”超模君很疑惑&#xff0c;凡尔赛文学的画风…

.NET 6新特性试用 | 可空引用类型

前言在查看《隐式using指令》功能时&#xff0c;我们在csproj中发现这样一个属性&#xff1a;那么&#xff0c;Nullable到底是干嘛的&#xff1f;可为空上下文严格来说&#xff0c;这不是新特性&#xff0c;而是C# 8.0引入的特性之一。该特性用于指示引用类型是否接受null值:只…

Android之Base64

Base64介绍 Base64是一种基于64个可打印字符来表示二进制数据的表示方法,从本质上看Base64编码就是将三字节转四字节。如将字符串“Man”用Base64编码。 如果数据的长度不是3的整数倍

这是不是帮女朋友拍照时的你?哈哈哈哈

1 就跟我房东说&#xff1a;现在打工人压力真大一样▼2 原来&#xff0c;连打工人都不配了吗&#xff1f;&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 原来这才是家大叶大▼4 给女朋友拍照时的你&#xff01;&#xff08;via.刘一杭三三 &#xff09;▼5 当法…

linux slub分配器浅析

在《linux内存管理浅析》中提到内核管理自己使用的内存时&#xff0c;使用了SLAB对象池。SLAB确实是比较复杂&#xff0c;所以一直以来都没有深入看一看。不过现在&#xff0c;linux内核中&#xff0c;SLAB已经被它的简化版--SLUB所代替。最近抽时间看了一下SLUB的代码&#xf…

openfire 插件开发例子

2019独角兽企业重金招聘Python工程师标准>>> 好久都没有写东西了。今天总结一下之前开发的一些openfire插件。 这次的插件需要提供一个HTTP的接口。通过HTTP来对openfire做一些操作。 插件的目录结构&#xff1a;项目名称“exampleplugin" src/main/javaorg/ji…

WPF实现一个彩虹按钮

WPF开发者QQ群&#xff1a; 340500857 | 微信群 -> 进入公众号主页 加入组织玩玩彩虹文字&#xff0c;这次用 LinearGradientBrush 并且制作成按钮&#xff0c;虽然没技术含量反而有些实用&#xff0c;这就是返璞归真吗。首先来回忆下 LinearGradientBrush 的用法。LinearG…

设计模式的分类和六大设计原则

学习设计模式我是大学研究《java与模式这本书》1024页&#xff0c;很多没有看懂&#xff0c;并且没有总结起来&#xff0c;这次一定要把设计原则和设计模式总结清楚。 设计模式的分类 设计模式分为三大类&#xff1a;创建型模式&#xff0c;共五种&#xff1a;工厂方法模式、…

nvidia控制面板点了没反应win7_为什么没有nvidia控制面板_win7没有nvidia控制面板怎么找回-系统城...

2016-10-31 16:15:46  浏览量&#xff1a;30668如果电脑显卡出现问题会导致屏幕画面不清楚&#xff0c;这时候win7系统自带nvidia控制面板就派上用场了。它能够对显卡进行设置&#xff0c;提升显卡功能&#xff0c;但有用户说win7怎么没有nvidia控制面板&#xff1f;找很久也…

公交车座椅上有个洞,竟是为了…很多人都不知道

全世界只有3.14 % 的人关注了爆炸吧知识坐公交车的时候你有没有发现公交车的座椅上通常来说中间都会有个洞洞的大小基本上刚好够一个手指头穿过那么这个洞到底有什么用呢&#xff1f;小编特意问了一圈同事们的回答真的脑洞大开有的说洞口刚好可以穿过手指是不是乘客无聊的时候可…

pythonresponse对象的属性_Scrapy中response属性以及内容提取

PythonPython开发Python语言Scrapy中response属性以及内容提取一.属性url &#xff1a;HTTP响应的url地址,str类型status&#xff1a;HTTP响应的状态码, int类型headers &#xff1a;HTTP响应的头部, 类字典类型, 可以调用get或者getlist方法对其进行访问body&#xff1a;HTTP响…

【转】学习apicloud和IOS之间的模块化使用

最近公司有使用APICloud发开的需求&#xff0c;需要我这边提供一些模块包得封装。因为没有也是刚接触APICloud&#xff0c;所以也就在看官方文档 。下面讲一讲我再使用过程中得一点点东西。 首先&#xff0c;下载官方SDK,下载最新版本的模块开发SDK&#xff0c;找到里面的Modul…

豪横!学术圈“造假之王”,200余篇论文有183篇论文被撤稿

全世界只有3.14 % 的人关注了爆炸吧知识导读&#xff1a;学术造假已经不再是什么新鲜话题&#xff0c;历史上的学术骗子也是数不胜数。其中骗子之王更是达到前无古人的地步&#xff0c;发表论文数212篇&#xff0c;因涉嫌造假而遭到撤稿的就达到了183篇之多。然而打假的过程并不…

学Dapr Actors 看这篇就够了

介绍Actor模式将Actor描述为最低级别的“计算单元”。换句话说&#xff0c;您在一个独立的单元&#xff08;称为actor&#xff09;中编写代码&#xff0c;该单元接收消息并一次处理一个消息&#xff0c;没有任何并发或线程。再换句话说&#xff0c;根据ActorId划分独立计算单元…

git之Pushing to the remote branch is not fast-forward错误解决

今天推送代码的时候报错了这个Pushing to the remote branch is not fast-forward,so the push has to be forced.The commits in the remote branch will be lost 错误&#xff0c;然后就出现这个效果&#xff0c;下面是图片。 问题&#xff08;Non-fast-forward&#xff09;的…