list删除操作 java.util.ConcurrentModificationException
首先大家先看一段代码:
public static void main(String[] args) {
List<String> listStr = new ArrayList<String>();
listStr.add("1");
listStr.add("2");
listStr.add("3");
listStr.add("4");
listStr.add("5");
System.out.println("listStr.size:::"+listStr.size());
for(String str:listStr){
if("3".equals(str)){
listStr.remove(str);
}
}
System.out.println("listStr.size:::"+listStr.size());
}
现象:
该程序会抛出一个 java.util.ConcurrentModificationException异常。
分析:
对 Collection 或 Map 进行迭代操作过程中尝试直接修改 Collection / Map 的内容时,会抛出java.util.ConcurrentModificationException 异常。 因为在修改数据时不能同步原有list中数据,当下一次循环时找不到数据。
解决办法:
Iterator 在工作的时候是不允许被迭代的对象被改变的,使用 Iterator 本身的方法 remove() 来删除对
象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
改后代码:
public static void main(String[] args) {
List<String> listStr = new ArrayList<String>();
listStr.add("1");
listStr.add("2");
listStr.add("3");
listStr.add("4");
listStr.add("5");
System.out.println("listStr.size:::"+listStr.size());
Iterator<String> ite = listStr.iterator();
while(ite.hasNext()){
String str = (String)ite.next();
if("3".equals(str)){
ite.remove();
}
}
System.out.println("listStr.size:::"+listStr.size());
}
补充:
或许有人可能会问如果我不用增强for循环,直接用.get(index)方法会不会报错?
代码如下:
for(int i = 0 ; i < listStr.size(); i++){
if("3".equals(listStr.get(i))){
listStr.remove(i);
}
}
现象:
listStr.size:::5
listStr.size:::4
大家可以看到通过list的下表索引来修改list数据是不会出错的。
分析:
大家可以这样认为:通过所引来循环时,jvm记录的是所引值,当移除当前对象后,其他元素的索引号不会同步改变。下次循环仍可以找到对应数据。而增强for循环,记录的是当前对象,当下次循环时,会先找到该对象,然后游标向下移,这时候找不到对象所以结果会混乱。
java.util.ConcurrentModificationException
【引言】
经常在迭代集合元素时,会想对集合做修改(add/remove)操作,类似下面这段代码:
- for (Iterator<Integer> it = list.iterator(); it.hasNext(); ) {
- Integer val = it.next();
- if (val == 5) {
- list.remove(val);
- }
- }
运行这段代码,会抛出异常java.util.ConcurrentModificationException。
【解惑】
(以ArrayList来讲解)在ArrayList中,它的修改操作(add/remove)都会对modCount这个字段+1,modCount可以看作一个版本号,每次集合中的元素被修改后,都会+1(即使溢出)。接下来再看看AbsrtactList中iteraor方法
- public Iterator<E> iterator() {
- return new Itr();
- }
它返回一个内部类,这个类实现了iterator接口,代码如下:
- private class Itr implements Iterator<E> {
- int cursor = 0;
- int lastRet = -1;
- int expectedModCount = modCount;
- public boolean hasNext() {
- return cursor != size();
- }
- public E next() {
- checkForComodification();
- try {
- E next = get(cursor);
- lastRet = cursor++;
- return next;
- } catch (IndexOutOfBoundsException e) {
- checkForComodification();
- throw new NoSuchElementException();
- }
- }
- public void remove() {
- if (lastRet == -1)
- throw new IllegalStateException();
- checkForComodification();
- try {
- AbstractList.this.remove(lastRet);
- if (lastRet < cursor)
- cursor--;
- lastRet = -1;
- // 修改expectedModCount 的值
- expectedModCount = modCount;
- } catch (IndexOutOfBoundsException e) {
- throw new ConcurrentModificationException();
- }
- }
- final void checkForComodification() {
- if (modCount != expectedModCount)
- throw new ConcurrentModificationException();
- }
- }
在内部类Itr中,有一个字段expectedModCount ,初始化时等于modCount,即当我们调用list.iterator()返回迭代器时,该字段被初始化为等于modCount。在类Itr中next/remove方法都有调用checkForComodification()方法,在该方法中检测modCount == expectedModCount,如果不相当则抛出异常ConcurrentModificationException。
前面说过,在集合的修改操作(add/remove)中,都对modCount进行了+1。
在看看刚开始提出的那段代码,在迭代过程中,执行list.remove(val),使得modCount+1,当下一次循环时,执行 it.next(),checkForComodification方法发现modCount != expectedModCount,则抛出异常。
【解决办法】
如果想要在迭代的过程中,执行删除元素操作怎么办?
再来看看内部类Itr的remove()方法,在删除元素后,有这么一句expectedModCount = modCount,同步修改expectedModCount 的值。所以,如果需要在使用迭代器迭代时,删除元素,可以使用迭代器提供的remove方法。对于add操作,则在整个迭代器迭代过程中是不允许的。 其他集合(Map/Set)使用迭代器迭代也是一样。
//获奖显示
public String prizeList(){
voteList = userWorksService.getAllRank();
UserWorks userWorks = new UserWorks();
Iterator<UserWorks> list = voteList.iterator();
Integer rank ;
while(list.hasNext()){
userWorks = list.next();
if(!("9".equals(userWorks.getAwardsRank()))){
rank = Integer.parseInt(userWorks.getAwardsRank())+2;
userWorks.setAwardsRank(rank +"");
allList.add(userWorks);
}
}
voteList.removeAll(allList);
return "prizeList";
}
list删除操作 java.util.ConcurrentModificationException的更多相关文章
- 再次踩bug:遍历删除list(java.util.ConcurrentModificationException)
再次踩bug:遍历删除list(java.util.ConcurrentModificationException) 使用 List<Long> list = new ArrayList& ...
- 为什么阿里巴巴禁止在 foreach 循环里进行元素的 remove/add 操作--java.util.ConcurrentModificationException
摘要 foreach循环(Foreach loop)是计算机编程语言中的一种控制流程语句,通常用来循环遍历数组或集合中的元素. 在阿里巴巴Java开发手册中,有这样一条规定: 但是手册中并没有给出具体 ...
- 遍历List过程中删除操作报java.util.ConcurrentModificationException错误
1:遍历List 同时 remove 元素,出现java.util.ConcurrentModificationException错误 @Test public void test3(){ List& ...
- 对ArrayList操作时报错java.util.ConcurrentModificationException null
用iterator遍历集合时要注意的地方:不可以对iterator相关的地方做添加或删除操作.否则会报java.util.ConcurrentModificationException 例如如下代码: ...
- Hashtable 删除元素, 抛出异常 java.util.ConcurrentModificationException
今天在对一个Hashtable对象进行 搜索 -> 删除 操作时遇到的一个问题,开始的使用我使用的是Hashtable的Iterator,然后直接执行: Hashtable.remove(key ...
- 集合循环删除问题-报错java.util.ConcurrentModificationException解析
java.util.ConcurrentModificationException 异常问题详解 环境:JDK 1.8.0_111 在Java开发过程中,使用iterator遍历集合的同时对集合进行修 ...
- JAVA循环迭代中删除或添加集合数据报java.util.ConcurrentModificationException错误
1.写出下面的输出结果 public class test{ public static void main(String [] args) List<String> list = new ...
- SpringMvc中Hashmap操作遇到 java.util.ConcurrentModificationException: null
代码按照网上修改为类似,还不能解决问题 for (Iterator<String> it = target.keySet().iterator(); it.hasNext(); ) { i ...
- java.util.ConcurrentModificationException 解决办法(转载)
今天在项目的中有一个需求,需要在一个Set类型的集合中删除满足条件的对象,这时想当然地想到直接调用Set的remove(Object o)方法将指定的对象删除即可,测试代码: public cla ...
随机推荐
- [cocos2d-x·解Bug]关于cocos2d-x游戏在android锁屏状态下播放Bgm的解决方法
最近<宠物联萌>在三星App上发布遇到一个问题:如果用户在锁定屏幕时解锁解到一半时取消解锁,这时用cocos2d-x开发的游戏就会出现游戏Bgm会恢复播放,但手机屏幕仍然是锁屏状态的Bug ...
- Java [Leetcode 101]Symmetric Tree
题目描述: Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). ...
- 【Java学习笔记】函数使用
package aaa; public class aaa { public static int add(int a,int b) { return a+b; } public static voi ...
- (转)HTTP协议详解
引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1. ...
- Windows下FFmpeg快速入门
本系列文章导航 Windows下FFmpeg快速入门 ffmpeg参数解释 mencoder和ffmpeg参数详解(Java处理视频) Java 生成视频缩略图(ffmpeg) 使用ffmpeg进行视 ...
- Mac下开发常用目录
1:Snippets Xcode 代码段的文件表示 ~/Library/Developer/Xcode/UserData/CodeSnippets/ 2: Services 可以添加workf ...
- 【转】linux中waitpid及wait的用法
原文网址:http://www.2cto.com/os/201203/124851.html wait(等待子进程中断或结束) 表头文件 #include<sys/types.h> ...
- 底部菜单栏(二) TabHost & RadioGroup 实现
需求:使用TabHost & RadioGroup实现底部菜单栏: 效果图: 实现分析: 1.目录结构: 代码实现: 1. activity_main.xml <?xml version ...
- UINavigationController 操作记录
//设置字体大小 颜色 { UIColor *color = [UIColor brownColor]; UIFont * font = [UIFont systemFontOfSize:20]; N ...
- Selenium用户扩展
Selenium用户扩展 这很容易扩展Selenium IDE加入自定义操作,断言和定位,策略,这是通过添加方法,在JavaScript的帮助下Selenium 对象原型.在启动时,Selenium会 ...