如何在Java中处理ConcurrentModificationException? 在循环中从ArrayList中删除元素时要当心...

从Java中从ArrayList中删除元素时常见的问题之一是ConcurrentModificationException。 如果您对索引使用经典的for循环或增强的for循环,并尝试使用remove()方法从ArrayList中remove()元素,则将获得C oncurrentModificationException但如果使用Iterator的remove方法或ListIterator的
remove()方法,那么您将不会遇到此错误,并且能够删除该元素。 这是Java中的一条不成文的规则,在遍历列表时,在集合支持故障安全迭代器(例如CopyOnWriteArrayList remove()之前,不应该add()remove()元素,该迭代器对列表的副本而不是原始列表进行操作。

出现此错误的主要问题是,它使开发人员混淆了列表正在被多个线程修改,这就是Java抛出此错误的原因,这不是事实。 大多数时候
即使没有多个线程修改列表,也会出现ConcurrentModificationException

这是用词不当,请不要为此而上当。 尽管似乎自然而然地认为其他线程可能试图同时修改集合,但这通常违反了Java规则。

在本文中,我将解释此错误,并且我们将提供许多代码示例,即使使用单线程也可以重现此代码,并了解如何在Java中修改ArrayList时如何避免并发修改错误。

顺便说一句,如果您不熟悉集合类(例如ArrayList本身),那么您应该参加在线课程,例如
Java基础知识:学习在Udemy上编写正确的代码是一个不错的起点。

单线程中的ConcurrentModificationException

这是在Java中再现并发修改异常的第一个示例。 在此程序中,我们使用增强的foreach循环遍历ArrayList并删除选择性元素,例如,使用ArrayList的remove方法删除匹配特定条件的元素。

例如,在下面的代码中,我们首先添加了几本不错的编程书,例如, Programming Pearls , Clean Code , Code Complete到ArrayList中,然后删除标题中带有Code的任何元素。

package beginner;import java.util.ArrayList;
import java.util.List;public class HelloWorldApp{public static void main(String... args){List<String> listOfBooks = new ArrayList<>();  listOfBooks.add("Programming Pearls");listOfBooks.add("Clean Code");listOfBooks.add("Effective Java");listOfBooks.add("Code Complete");// Using forEach loop to iterate and removing // element during iteration will throw // ConcurrentModificationException in Javafor(String book: listOfBooks){if(book.contains("Code"));{listOfBooks.remove(book);}}}}
Output
Exception in thread "main" java.util.ConcurrentModificationExceptionat java.util.ArrayList$Itr.checkForComodification(Unknown Source)at java.util.ArrayList$Itr.next(Unknown Source)at beginner.HelloWorldApp.main(HelloWorldApp.java:18)

您可以看到即使我们只有一个线程,即与ArrayList一起运行的主线程,也会出现此错误。 之所以会出现ConcurrentModification错误,是因为我们没有使用Iterator,而是仅调用listOfBooks.remove()方法。

在这段代码中,我使用的Java 1.5增强的for循环,你必须知道如何for循环增强 Java中的作品。

for循环和增强的for循环之间的区别在于,以后内部使用Iterator遍历集合的所有元素。 有关更深入的讨论,请参见此处

使用Classical for循环和ArrayList.remove(index)

这是从ArrayList中删除元素的另一个有趣的代码示例。 令人惊讶的是,当您第一次运行此代码时,它不会引发ConcurrentModificationException吗? 你知道为什么吗?

好吧,在查看代码后的解释之前,请尝试一下。 确实是有关Java编程语言和Collection框架的此类次要细节,这将使您成为一名优秀的开发人员,并且如果您正在为此做好准备,还将帮助您获得Java认证 。

package beginner;import java.util.ArrayList;
import java.util.List;public class HelloWorldApp{public static void main(String... args){List<String> listOfBooks = new ArrayList<>();  listOfBooks.add("Programming Pearls");listOfBooks.add("Clean Code");listOfBooks.add("Effective Java");listOfBooks.add("Code Complete");System.out.println("List before : " + listOfBooks);for(int i=0; i<listOfBooks.size(); i++){String book = listOfBooks.get(i);if(book.contains("Programming")){System.out.println("Removing " + book);listOfBooks.remove(i); // will throw CME}}System.out.println("List after : " + listOfBooks);}}Output
List before : [Programming Pearls, Clean Code, Effective Java, Code Complete]
Removing Programming Pearls
List after : [Clean Code, Effective Java, Code Complete]

这段代码不会引发ConcurrentModificationException因为在这里我们没有使用 Iterator,而是在使用传统的for循环。

是Iterator引发ConcurrentModificationException ,而不是ArrayList的remove方法,因此在下面的代码中看不到该错误。

如果查看ArrayList.java的代码,您会注意到有一个实现Iterator接口的嵌套类,并且next()方法调用checkForComodification()函数,该函数实际上检查ArrayList在迭代过程中是否已修改,如果modCount没有, “T配以expectedModCount则抛出ConcurrentModificationException

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

此类问题在Oracle Java认证中也很受欢迎,例如OCAJP( 1z0-808 )和OCPJP( 1Z0-809 ),因此,如果您准备参加这些考试,则应该知道答案。

这是ArrayList.java类的完整代码片段,供您快速参考:

使用迭代器,但使用ArrayList的remove方法

现在,让我们看另一个代码示例,其中Java程序员认为他已正确完成了所有工作,但仍收到并发修改异常。 您能发现错误吗? 这确实很常见,我在Java论坛,StackOverflow和要求解决此问题的Facebook Java组上经常看到这种代码。

package beginner;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class HelloWorldApp{public static void main(String... args){List<String> listOfBooks = new ArrayList<>();  listOfBooks.add("Programming Pearls");listOfBooks.add("Clean Code");listOfBooks.add("Effective Java");listOfBooks.add("Code Complete");Iterator<String> iterator = listOfBooks.iterator();while(iterator.hasNext()){String book = iterator.next();listOfBooks.remove(book);}}}Output
Exception in thread "main" java.util.ConcurrentModificationExceptionat java.util.ArrayList$Itr.checkForComodification(Unknown Source)at java.util.ArrayList$Itr.next(Unknown Source)at beginner.HelloWorldApp.main(HelloWorldApp.java:18)

这段代码的真正问题在于,即使代码使用Iterator遍历ArrayList ,也并不是真正使用Iterator.remove()方法删除该元素。 它只是使用Iterator获取下一个元素,但调用ArrayList.remove()方法删除该元素。

我知道,当您知道原因时就很容易了,但实际上,很多时候程序员甚至要花几个小时才能弄清楚问题出在哪里。 因此,请当心。

顺便说一句,如果您正在学习Java,那么我建议加入Complete Java Masterclass,以更好地学习Java并避免此类常见错误。

删除元素的正确方法是使用Iterator的remove方法

最后,这是在迭代过程中从ArrayList删除元素的正确方法。 在此示例中,我们使用Iterator进行了迭代以及删除了元素。 该代码还可以,但是有一个严重的限制,您只能使用此代码删除当前元素。 您不能从Java中的ArrayList中删除任何任意元素。

package beginner;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class HelloWorldApp{public static void main(String... args){List<String> listOfBooks = new ArrayList<>();  listOfBooks.add("Programming Pearls");listOfBooks.add("Clean Code");listOfBooks.add("Effective Java");listOfBooks.add("Code Complete");System.out.println("List before : " + listOfBooks);Iterator<String> iterator = listOfBooks.iterator();while(iterator.hasNext()){String book = iterator.next();System.out.println("Removing " + book);iterator.remove();}System.out.println("List after : " + listOfBooks);}}
Output
List before : [Programming Pearls, Clean Code, Effective Java, Code Complete]
Removing Programming Pearls
Removing Clean Code
Removing Effective Java
Removing Code Complete
List after : []

同样的行为也适用于ListIterator 。 我的意思是您可以用ListIterator替换Iterator,并且代码可以正常工作。 ListIterator还允许您在两个方向上进行导航,即向前和向后导航。

这就是在迭代过程中如何从ArrayList中删除元素时如何避免ConcurrentModificationException的全部内容。 您可以使用相同的技术来避免ConcurrentModificationException同时从具有快速失败的Iterator的任何其他集合类中删除元素,例如LinkedList。 顺便说一句,如果您不熟悉Java编程,那么可以参加一门很好的综合课程,例如Java Basics:学习在Udemy上编写正确的方法 ,可以帮助您更好更快地学习Java。

您可能喜欢的其他Java故障排除指南

如何在Java中解决ArrayIndexOutOfBoundsException? ( 指南 )
如何在Java中解决NullPointerException? (指南)
如何解决“系统找不到指定的路径”错误? ( 解决方案 ) 从命令行运行Java程序时如何解决NoClassDefFoundError? ( 解决方案 ) 如何解决Android Studio中的“找不到JVM,请安装64位JDK”错误? ( 解决方案 ) 如何处理JDBC和MySQL中SQLException“找不到合适的驱动程序”错误? ( 指南 ) 如何解决Java中的NumberFormatException? ( 指南 ) 如何解决Minecraft – java.lang.UnsatisfiedLinkError:lwjgl64.dll:访问被拒绝? ( 解决方案 ) 如何在Java中修复java.lang.ArrayIndexOutOfBoundsException:1? ( 解决方案 ) 如何修复java.net.SocketException:软件导致连接中止:recv失败( 修复 )

感谢您阅读本教程,如果您喜欢本教程,请与您的朋友和同事分享。 如果您有任何问题或建议,请发表评论。

翻译自: https://www.javacodegeeks.com/2018/01/deal-concurrentmodificationexception-java-beware-removing-elements-arraylist-loop.html

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

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

相关文章

Linux 命令之 zip -- 压缩文件

文章目录一、命令介绍二、常用选项三、命令示例&#xff08;一&#xff09;压缩指定目录及其包含的内容&#xff08;二&#xff09;压缩指定目录及其包含的内容&#xff0c;并选择压缩效率一、命令介绍 zip 命令可以将一个或多个文件放入一个压缩存档中&#xff0c;文件经它压…

南安职业中专学校计算机专业,南安职专:国家级重点职业中专学校

原标题&#xff1a;南安职专:国家级重点职业中专学校学校创办于1984年&#xff0c;现有教职工252人&#xff0c;在校生4152人。2004年被首批重新确认为国家级重点职业中专学校&#xff0c;2012年9月被确认为国家中等职业教育改革发展示范学校建设项目校。2016年1月份被确认为福…

python eel 多线程_Python 基础

input() 用于输入print() 用于输出数据类型:1、整数 、浮点数‘ / ‘ 表示除 得出的结果一定是个浮点型.‘ // ‘ 表示除 得出的结果一定是整数.(如果是小数会自动取整)‘ % ‘ 表示除 取余数(自动取得小数点后面的数)2、字符串(‘’ / “”)可以使用 ‘ \ ‘ 转义, r表示内部的…

Linux 命令之 unzip -- 解压缩文件

文章目录一、命令介绍二、命令选项三、命令示例&#xff08;一&#xff09;解压缩文件&#xff08;二&#xff09;将指定压缩文件解压到指定目录下&#xff08;三&#xff09;查看压缩包内的文件列表及有关的压缩信息&#xff08;四&#xff09;验证压缩文件是否完整一、命令介…

网络研讨室_网络研讨会:Java 9的第一印象–构建可伸缩企业应用程序的新方法...

网络研讨室在此网络研讨会上听我们对新Java版本的一些初步想法 关于Java 9的新版本&#xff0c;有很多宣传。将Java平台迁移到模块上&#xff0c;由Mark Reinhold领导的专门团队进行了近十年的艰苦工作。 除了备受期待的Project Jigsaw&#xff0c;此版本还包含许多其他令人兴…

react 日历组件_anujs1.5.1支持React.Suspense与lazy

React16是一个实验版本&#xff0c;除了测试它的新fiber架构外&#xff0c;还添加了大量新功能。其他React.Suspense与React.lazy就是重磅中的重磅。随着前端的APP化&#xff0c;不断集成功能&#xff0c;页面越来越大&#xff0c;bundle size以MB为单位&#xff0c;我们需要拆…

计算机永远无法处理日语所具有的暧昧性,计算机永远无法处理日语所具有的暧昧性。( )...

计算机永远无法处理日语所具有的暧昧性。( )更多相关问题[单选] 分体式变频空调器的节流装置选用的是()[单选] 当制冷压缩机效率降低时&#xff0c;其()[判断题] 流体以层流流态换热强度要强于湍流流态强度[单选] 一次回风式空调系统的调节方法&#xff0c;是控制()&#xff0c…

Linux 命令之 xz -- POSIX 平台的具有高压缩率的压缩工具

文章目录一、命令介绍二、常用选项三、命令示例&#xff08;一&#xff09;压缩文件&#xff0c;压缩成功后删除原文件&#xff08;二&#xff09;解压文件&#xff0c;且不删除原文件&#xff08;三&#xff09;根据自定义的压缩率压缩文件&#xff08;四&#xff09;借助 xar…

packt_Packt发行的$ 5 Java编程书籍:精通Java 9,Java 9高性能

packt你好&#xff0c;极客&#xff01; 今天&#xff0c;我们为您带来一些激动人心的消息&#xff01; Java Code Geeks和Packt联手为您提供广泛的书籍库每周折扣。 本周&#xff0c;我们提供Java相关书籍的折扣&#xff0c;以帮助您了解和掌握Java。 他们全都打折到每本书5…

redis 发布订阅实际案例_【赵强老师】Redis的消息发布与订阅

欢迎关注赵强老师微信公众号&#xff1a;myitshareRedis 作为一个publish/subscribe server&#xff0c;起到了消息路由的功能。订阅者可以通过subscribe和psubscribe命令向Redis server订阅自己感兴趣的消息类型&#xff0c;当发布者通过publish命令向Redis server发送特定类型…

上海大学计算机考研数一数二,2021年考研成绩出来了!上海大学数二人均135+,“神仙打架”现场...

原标题&#xff1a;2021年考研成绩出来了&#xff01;上海大学数二人均135&#xff0c;“神仙打架”现场文/跳跳妈妈谈教育2000年代初期&#xff0c;电视上流行这样一句话&#xff0c;“二十一世纪什么最珍贵&#xff1f;人才&#xff01;”时间如长河不断流逝&#xff0c;步入…

对称密钥加密算法 对称轮数_选择Java加密算法第2部分–单密钥对称加密

对称密钥加密算法 对称轮数抽象 这是涵盖Java加密算法的三部分博客系列的第2部分。 该系列涵盖如何实现以下功能&#xff1a; 使用SHA–512散列 AES–256 RSA–4096 这第二篇文章详细介绍了如何实现单密钥对称AES-256加密。 让我们开始吧。 免责声明 这篇文章仅供参考。 在…

Linux 命令之 unxz -- 解压缩文件

文章目录一、命令介绍二、命令示例&#xff08;一&#xff09;解压文件&#xff08;二&#xff09;将指定的压缩文件解压缩到指定的目录下&#xff0c;且可以重命名一、命令介绍 unxz 命令用于解压缩使用 xz 压缩的文件包&#xff0c;实际 unxz 相当于 xz -d 二、命令示例 &…

计算机配置界面在那,在哪里设置关机画面?设置为原来的经典界面?

电脑故障现象&#xff1a;我用的系统是winxp&#xff0c;关机出现的画面是那种下拉式菜单“注销、重启、关机、取消”&#xff0c;我想用的不是这种下拉式菜单&#xff0c;是并列图标那种&#xff0c;请问在哪里设置&#xff1f;(电脑入门到精通网 www.58116.cn)一般解决方法&a…

程序代码移植和烧录需要注意什么_购买建站模板需要注意什么问题

购买建站模板需要注意什么问题?现在市面上出现的建站工具质量参差不齐&#xff0c;但是如此多的建站模板&#xff0c;应该选择哪个呢&#xff1f;如此多的建站工具平台应该怎么样选择呢&#xff1f;这里我们来聊一聊。北京网站建设公司—东浩联创现在非常多站长都会购买一些定…

java字符串各个字符计数_没有科学计数法的Java十进制数的简单字符串表示形式...

java字符串各个字符计数Java中用于十进制数字的主要类型 /对象是float / Float &#xff0c; double / Double和BigDecimal 。 在每种情况下&#xff0c;其“默认”字符串表示形式都是“计算机科学计数法”。 这篇文章演示了一些简单的方法&#xff0c;可以在没有科学符号的情况…

python操纵excel的方法_python操作Excel的几种方式

Python对Excel的读写主要有xlrd、xlwt、xlutils、openpyxl、xlsxwriter几种。首先你的本地要有包文件&#xff0c;安装上面的包文件如下图1.xlrd主要是用来读取excel文件import xlrdworkbook xlrd.open_workbook(u有趣装逼每日数据及趋势.xls)sheet_names workbook.sheet_name…

计算机线性输入录音原理,耳机输出的模拟信号-怎样把声音通过线路录入电脑?比方说,收音机的耳机输出孔,接线(串 爱问知识人...

啊&#xff1f;有这样的东西吗&#xff1f;想把收音机里的声音录下来很简单。你在电脑上收听就可以了。这和软件无关。是因为硬件。买了转接头也是没用的。因为计算机声卡只能通过计算机来放音然后录制。其实你指的就是放音录制而不是通过其他线路来录制。这和外放的设备无关。…

Linux 如何查看命令所在位置/查看命令文件所在位置

文章目录whichtypewhereiswhich which 命令的作用是在环境变量 PATH 所指定的路径中&#xff0c;搜索某个系统命令的位置&#xff0c;并且返回第一个搜索结果。 查看命令详情&#xff0c;猛戳 《Linux 命令之 which – 查找并显示给定命令的绝对路径》 [roothtlwk0001host ~…

java 方法 示例_Java 9示例–收集的工厂方法–创建不可修改的列表,集合和映射...

java 方法 示例大家好&#xff0c;这是我在该博客上发表的有关Java 9功能的第一篇文章&#xff0c;今天您将了解我最喜欢的功能“收集的工厂方法” &#xff0c;它是JEP 269的一部分。JEP代表JDK增强建议。 如果您曾经在Groovy或Kotlin工作过&#xff0c;那么您就会知道使用集合…