增强for循环 java.util.ConcurrentModificationException
Java中的Iterator功能比较简单,并且只能单向移动:
(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
(2) 使用next()获得序列中的下一个元素。
(3) 使用hasNext()检查序列中是否还有元素。
(4) 使用remove()将迭代器新返回的元素删除。
迭代器应用:
list l = new ArrayList();
l.add("aa");
l.add("bb");
l.add("cc");
for (Iterator iter = l.iterator(); iter.hasNext();) {
String str = (String)iter.next();
System.out.println(str);
}
/*迭代器用于while循环
Iterator iter = l.iterator();
while(iter.hasNext()){
String str = (String) iter.next();
System.out.println(str);
}
*/
Iterator升级
【注】在AbstractList中,有一个属性modCount,这个属性是跟踪List中数据被修改的次数,任何对List的add/remove操作,都将导致modCount++。
Iterator是List一个视图,其最终还是操作List的存储结构。在使用iterator遍历时,remove()操作,会导致modCount++,因为有expectedModCount=modCount,即在 iterator中remove数据,会带来expectedModCount与modCount值的同步。
在Iterator遍历时,next(),remove()方法会校验expectedModCount与modCount值是否一致,如果不一致,就意味着这List数据在iterator外部被修改,此时iterator遍历将会造成 ConcurrentModificationException。
AbstractList不仅支持普通的Iterator,还支持ListIterator(ArrayList,LinkedList均支持),ListIterator增加了遍历时双向游标能力(previous,next),增加了add方法。add方法和remove方法一样也做了expectedModCount和modCount一致性校验。
在单线程操作的情况下,在DAO层查询到数据集合后,返回到service层做业务处理,要求:遍历数据集合,判断不符合条件的元素,做删除操作。
在用foreach和 Iterator 都会发生java.util.ConcurrentModificationException。
看一下JavaDoc对java.util.ConcurrentModificationException异常的描述:
当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
查看源码后终于发现了原因是因为:
迭代器的modCount和expectedModCount的值不一致。
单线程中该异常出现的原因是:对一个集合遍历的同时,有对该集合进行了增删的操作。导致AbstarctList的modCount和expectedModCount的值不一致。
而我们要做的就是将需要操作的元素放到中间元素中,并记录操作标志位。在遍历结束后进行增删操作。
或自定义迭代器复写其中的相关操作,在操作结束后添加expectedModCount = modCount;
多线程中更容易出现该异常,当你在一个线程中对一数据集合进行遍历,正赶上另外一个线程对该数据集合进行增删操作。
解决方案:
1)在使用iterator迭代的时候使用synchronized或者Lock进行同步;
2)使用并发容器CopyOnWriteArrayList代替ArrayList和Vector。
以下是Demo:推荐大家使用for循环进行遍历集合,在for循环中做增删操作。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; public class Test { // 出现java.util.ConcurrentModificationException
public List<String> m1(List<String> list) {
for (String temp : list) {
if ("3".equals(temp)) {
list.remove(temp);
}
}
return list; }
// 出现java.util.ConcurrentModificationException
public List<String> m2(List<String> list) {
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String temp = iterator.next();
if ("3".equals(temp)) {
list.remove(temp);
} }
return list; }
//successful!
public List<String> m3(List<String> list) {
for (int i = 0; i < list.size(); i++) {
if ("3".equals(list.get(i))) {
list.remove(i);
}
}
return list; }
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
list.add("3");
Test test = new Test();
List<String> listTemp = test.m1(list);
System.out.println(listTemp.toString());
}
}
Iterator 在工作的时候是不允许被迭代的对象被改变的。
但你可以使用 Iterator 本身的方法 remove() 来删除对象,Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
正确的在遍历的同时删除元素的姿势:
Iterator<Student> stuIter = students.iterator();
while (stuIter.hasNext()) {
Student student = stuIter.next();
if (student.getId() == 2)
stuIter.remove();//这里要使用Iterator的remove方法移除当前对象,如果使用List的remove方法,则同样会出现ConcurrentModificationException
}
参考:https://mp.weixin.qq.com/s?__biz=MzI3NzE0NjcwMg%3D%3D&mid=2650121134&idx=1&sn=a34a1bd547f00e479e9f6dbde8848fe4&chksm=f36bbe8fc41c3799d1bb2c781f81f51e28651d2fb8eb5670a31caac5ba782b66416e5fdf1b1c&mpshare=1&scene=23&srcid=0414ouzb2yYypPWh2K0QVhtY%23rd
增强for循环 java.util.ConcurrentModificationException的更多相关文章
- 为什么阿里巴巴禁止在 foreach 循环里进行元素的 remove/add 操作--java.util.ConcurrentModificationException
摘要 foreach循环(Foreach loop)是计算机编程语言中的一种控制流程语句,通常用来循环遍历数组或集合中的元素. 在阿里巴巴Java开发手册中,有这样一条规定: 但是手册中并没有给出具体 ...
- 集合循环删除问题-报错java.util.ConcurrentModificationException解析
java.util.ConcurrentModificationException 异常问题详解 环境:JDK 1.8.0_111 在Java开发过程中,使用iterator遍历集合的同时对集合进行修 ...
- java foreach循环抛出异常java.util.ConcurrentModificationException
代码如下: for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) { if (Integer.parseInt(i ...
- JAVA循环迭代中删除或添加集合数据报java.util.ConcurrentModificationException错误
1.写出下面的输出结果 public class test{ public static void main(String [] args) List<String> list = new ...
- LinkedList - java.util.ConcurrentModificationException
package com.test.io; import java.io.BufferedReader; import java.io.FileNotFoundException; import jav ...
- list删除操作 java.util.ConcurrentModificationException
首先大家先看一段代码: public static void main(String[] args) { List<String> listStr = new ArrayList<S ...
- Java Bug -- java.util.ConcurrentModificationException
java.util.ConcurrentModificationException at java.util.ArrayList$ArrayListIterator.next(ArrayList.ja ...
- 浅谈java.util.ConcurrentModificationException(并发修改异常)
java中的list集合是我们经常使用的集合,而对集合进行增加和删除元素是我们最常用的操作.那么在什么时候对list集合什么样的操作,就会发生java.util.ConcurrentModificat ...
- 再次踩bug:遍历删除list(java.util.ConcurrentModificationException)
再次踩bug:遍历删除list(java.util.ConcurrentModificationException) 使用 List<Long> list = new ArrayList& ...
随机推荐
- bzoj1934 Vote 善意的投票 最小割(最大匹配)
题目传送门 题目大意:很多小朋友,每个小朋友都有自己的立场,赞成或者反对,如果投了和自己立场不同的票会得到一个能量.又有很多朋友关系,如果一个人和他的一个朋友投的票不同,也会得到一个能量,现在问,通过 ...
- 109th LeetCode Weekly Contest Number of Recent Calls
Write a class RecentCounter to count recent requests. It has only one method: ping(int t), where t r ...
- mysql--外键(froeign key)-----------MySQL外键使用详解
如果一个实体的某个字段指向另一个实体的主键,就称为外键被指向的实体,称之为主实体(主表),也叫父实体(父表).负责指向的实体,称之为从实体(从表),也叫子实体(子表) 作用:用于约束处于关系内的实体增 ...
- 用 Koa 提供 Restful service 和查询 MongoDB 的例子
const path = require('path'); const Koa = require('koa'); const app = new Koa(); const compose = req ...
- [转] 从零开始学Spring Boot
[From] http://412887952-qq-com.iteye.com/blog/2291496 一个博主写的spring boot系列文章,很赞!
- PIE SDK地图显示范围截图
1.1. 功能简介 地图显示范围截图是将当前地图显示的范围进行输出.输出的 格式是png.bmp,主要思路就是通过IActiveView接口下的Output()方法进行输出 1.2. 功能实现说明 2 ...
- 转 LIST INCARNATION OF DATABASE
incarnation在英文中是“化身”的意思. 那么在oracle中,它又是什么意思呢?有什么作用呢? 我们看一些基本概念 Current Incarnation(当前化身):数据库当前正在使用的化 ...
- vue之element-ui文件上传
vue之element-ui文件上传 文件上传需求 对于文件上传,实际项目中我们的需求一般分两种: 对于单个的文件上传,比如拖动上传个图片之类的,或者是文件. 和表单一起实现上传(这种情况一般都是 ...
- JetBrains PyCharm(Community版本)的下载、安装和初步使用
不多说,直接上干货! 首先谈及这款软件,博主我用的理由:搞机器学习和深度学习! 想学习Python的同学们,在这里隆重介绍一款 Python 的开发工具 pyCharm IDE.这是我最喜欢的 Pyt ...
- 安卓获取输入法高度与ViewTreeObserver讲解
目录 安卓获取输入法高度 前言 清单 开始 ViewTreeObserver讲解 获取输入法高度原理 思路 实现 关于ViewTreeObserver 定义 继承 摘要 获取View高度的三种方法 源 ...