被迭代的对象在迭代过程中不允许对其修改

java.util.ConcurrentModificationException 解决办法

今天在项目的中有一个需求,需要在一个Set类型的集合中删除满足条件的对象,这时想当然地想到直接调用Set的remove(Object o)方法将指定的对象删除即可,测试代码:
   public class Test {
    public static void main(String[] args) {
        User user1 = new User();
        user1.setId(1);
        user1.setName("zhangsan");

User user2 = new User();
        user2.setId(2);
        user2.setName("lisi");

Set userSet = new HashSet();
        userSet.add(user1);
        userSet.add(user2);
        for (Iterator it = userSet.iterator(); it.hasNext();) {
            User user = (User) it.next();
            if (user.getId() == 1) {
                userSet.remove(user);
            }

if (user.getId() == 2) {
                user.setName("zhangsan");
            }
        }
        for(Iterator it = userSet.iterator(); it.hasNext(); ) {
            User user = (User) it.next();
            System.out.println(user.getId() + "=>" + user.getName());
        }
    }
}
但运行程序的时候,却发现出错了:
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
    at java.util.HashMap$KeyIterator.next(Unknown Source)
    at test.Test.main(Test.java:23)

从API中可以看到List等Collection的实现并没有同步化,如果在多 线程应用程序中出现同时访问,而且出现修改操作的时候都要求外部操作同步化;调用Iterator操作获得的Iterator对象在多线程修改Set的时 候也自动失效,并抛出java.util.ConcurrentModificationException。这种实现机制是fail-fast,对外部 的修改并不能提供任何保证。

网上查找的关于Iterator的工作机制。Iterator是工作在一个独立的线程中,并且拥有一个 mutex锁,就是说Iterator在工作的时候,是不允许被迭代的对象被改变的。Iterator被创建的时候,建立了一个内存索引表(单链表),这 个索引表指向原来的对象,当原来的对象数量改变的时候,这个索引表的内容没有同步改变,所以当索引指针往下移动的时候,便找不到要迭代的对象,于是产生错 误。List、Set等是动态的,可变对象数量的数据结构,但是Iterator则是单向不可变,只能顺序读取,不能逆序操作的数据结构,当 Iterator指向的原始数据发生变化时,Iterator自己就迷失了方向。
如何才能满足需求呢,需要再定义一个List,用来保存需要删除的对象:
List delList = new ArrayList();
最后只需要调用集合的removeAll(Collection con)方法就可以了。
public class Test {
    public static void main(String[] args) {
        boolean flag = false;
        User user1 = new User();
        user1.setId(1);
        user1.setName("shangsan");

User user2 = new User();
        user2.setId(2);
        user2.setName("lisi");

Set userSet = new HashSet();
        userSet.add(user1);
        userSet.add(user2);
        List delList = new ArrayList();
        for (Iterator it = userSet.iterator(); it.hasNext();) {
            User user = (User) it.next();
            if (user.getId() == 1) {
                delList.add(user);
            }

if (user.getId() == 2) {
                user.setName("zhangsan");
            }
        }
        userSet.removeAll(delList);

for(Iterator it = userSet.iterator(); it.hasNext(); ) {
            User user = (User) it.next();
            System.out.println(user.getId() + "=>" + user.getName());
        }
    }
}

时间: 2024-10-11 11:51:10

被迭代的对象在迭代过程中不允许对其修改的相关文章

测试人员眼中的app版本迭代过程中的问题

测试人员眼中的app版本迭代过程的问题     --记一次app新版本的开发测试过程 1. 前言 自从8月初入职当前的公司以来,在这一期的版本迭代过程中,第一次独立承担app部分的全部测试设计及需求跟踪,从头至尾跟踪了需求分析到开发测试上线的整体过程,和曾经做过的各种测试类型相比,它没有想象的那么好,也没有想象的那么坏.应了那句老话,梨子好不好吃,自己尝了才知道. 经历完整个迭代之后,感慨良多.在这里梳理整个过程,以测试的角度来分析整个迭代过程,作为以后工作的参考. 2. 简介 2.1 项目及公

List在迭代过程中如何进行增删改查 ListIterator知识点

/** *    案例: 有如下一个list集合,需求,遍历集合,当集合中等于"five"元素,那么就插入元素"four". * *    解决问题的过程中发现: *  在迭代过程中,如果使用了集合的方法进行增删改查操作,那么迭代器会抛出 异常 ConcurrentModificationException. 原因是,迭代器不知道集合中的变化,容易发生调用的不确定性. 解决办法: 在迭代时,不要使用集合的方法进行操作元素.可以使用迭代器的子接口ListIterato

Python 可迭代的对象、迭代器和生成器

迭代是数据处理的基石.扫描内存中放不下的数据集时,我们要找到一种惰性获取数据项的方式,即按需一次获取一个数据项.这就是迭代器模式(Iterator pattern). p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 25.0px Helvetica } Sentence类第1版:单词序列 我们要实现一个 Sentence 类,以此打开探索可迭代对象的旅程.我们向这个类的构造方法传入包含一些文本的字符串,然后可以逐个单词迭代.第 1 版要实现序列协议,这

流畅的python第十四章可迭代的对象,迭代器和生成器学习记录

在python中,所有集合都可以迭代,在python语言内部,迭代器用于支持 for循环 构建和扩展集合类型 逐行遍历文本文件 列表推导,字典推导和集合推导 元组拆包 调用函数时,使用*拆包实参 本章涵盖的话题 语言内部使用 iter(...) 内置函数处理可迭代对象的方式如何使用 Python 实现经典的迭代器模式详细说明生成器函数的工作原理如何使用生成器函数或生成器表达式代替经典的迭代器如何使用标准库中通用的生成器函数如何使用 yield from 语句合并生成器案例分析:在一个数据库转换工

第14章 可迭代的对象、迭代器和生成器

#第14章 可迭代的对象.迭代器和生成器 # 迭代是数据处理的基石.扫描内存中放不下的数据集时,我们要找到一种惰性获取数据项的方式,即按需一次获取一个数据项.这就是迭代器模式(Iterator pattern). # 所有生成器都是迭代器,因为生成器完全实现了迭代器接口. # 迭代器用于从集合中取出元素:而生成器用于"凭空"生成元素. # 14.1 Sentence类第1版:单词序列 # 示例 14-1 sentence.py:把句子划分为单词序列 import re import r

流畅的python14 章可迭代的对象、迭代器 和生成器

可迭代的对象.迭代器和生成器 迭代是数据处理的基石.扫描内存中放不下的数据集时,我们要找到一种惰性获取数据项的方式,即按需一次获取一个数据项.这就是迭代器模式(Iterator pattern). 迭代器用于从集合中取出元素:而生成器用于“凭空”生成元素.通过斐波纳契数列能很好地说明二者之间的区别:斐波纳契数列中的数有无穷个,在一个集合里放不下.不过要知道,在 Python社区中,大多数时候都把迭代器和生成器视作同一概念. Sentence类 单词序列 import re import repr

java之List接口 迭代过程中添加元素

list接口:有下标,存取有序,允许有重复的元素(equals方法),比较是否有重复的元素. 常用接口实现类:ArrayList集合    Linkedlist集合 1 //有序 可重复 有下标值 2 List<String> arr=new ArrayList<String>();//此时多态创建对象,仍为集合 3 arr.add("1"); 4 //向指定的位置上添加元素,原有元素后移 5 arr.add(0,"2"); 6 arr.ad

【Thinking In Java零散笔记】对于持有对象一章中的显示系统环境变量代码分析

今天仍旧进行着学习java的计划.在学习到持有对象一章中,看到了如下代码: 1 import java.util.*; 2 3 public class EnvironmentVariables { 4 public static void main(String[] args) { 5 for(Map.Entry entry: System.getenv().entrySet()) { 6 System.out.println(entry.getKey() + ": " + 7 en

javascript获取对象直接量中的属性和属性值

javascript获取对象直接量中的属性和属性值:所谓的对象直接量简单来说就是,由大括号包裹的键值对列表,例如: var antzone={ webName:"蚂蚁部落", address:"青岛市南区", age:2 } 下面介绍一下如何获取对象直接量中的属性和属性值,代码如下: var antzone={ webName:"蚂蚁部落", address:"青岛市南区", age:2 } for(var prop in a