在对List、Set、Map执行遍历删除或添加等改变集合个数的操作时,不能使用普通的while、for循环或增强for。会抛出ConcurrentModificationException异常或者没有达到删除的需求。在遍历时删除元素,需要使用迭代器的方式。

ArrayList源码中说明的报异常原因:

* <p>The iterators returned by this class's <tt>iterator</tt> and

 * <tt>listIterator</tt> methods are <i>fail-fast</i>: if the list is

 * structurally modified at any time after the iterator is created, in any way

 * except through the iterator's own <tt>remove</tt> or <tt>add</tt> methods,

 * the iterator will throw a {@link ConcurrentModificationException}.  Thus, in

 * the face of concurrent modification, the iterator fails quickly and cleanly,

 * rather than risking arbitrary, non-deterministic behavior at an undetermined

 * time in the future.<p>

(翻译:通过类的iterator和listiterator方法获取到的迭代器是快速失败迭代器:如果list在迭代器生成之后发生了结构性的改变,迭代器将抛出ConcurrentModificationException,但是当使用迭代器自己的remove或add方法时,不会抛出此异常。也就是说,当面对并发修改时,迭代器快速失败,而不是冒在未来不确定的时间发生不确定的行为的危险。)

 *

 * Note that the fail-fast behavior of an iterator cannot be guaranteed

 * as it is, generally speaking, impossible to make any hard guarantees in the

 * presence of unsynchronized concurrent modification.  Fail-fast iterators

 * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.

 * Therefore, it would be wrong to write a program that depended on this

 * exception for its correctness: <i>the fail-fast behavior of iterators

 * should be used only to detect bugs.</i><p>

(翻译:需要注意的是迭代器不保证快速失败行为一定发生,因为一般来说不可能对是否发生了不同步并发修改做任何硬性的保证。快速失败迭代器会尽最大努力抛出ConcurrentModificationException异常。因此,写一个通过是否出现这种异常来判断是否正确的程序是错误的。快速失败行为的正确用法是仅用于检测异常。)

代码示例:

public class CollectionRemoveDemo {

    public static void main(String[] args) {
        ListRemove();
        System.out.println("-----------------------------------------------------------------------------------------------");
        SetRemove();
        System.out.println("-----------------------------------------------------------------------------------------------");
        MapRemove();
    }

    public static void ListRemove(){
        List<String> strList = new ArrayList<String>();
        strList.add("aaaa");
        strList.add("bbbb");
        strList.add("cccc");
        strList.add("cccc");
        strList.add("dddd");
        for(String str : strList){
            System.out.println(str);
        }
        System.out.println("init List size:" + strList.size());
        Iterator<String> it = strList.iterator();
        while(it.hasNext()){
            String str = it.next();
            if(str.equals("cccc")){
                it.remove();
            }
        }
        for(String str : strList){
            System.out.println(str);
        }
        System.out.println("removed List size:" + strList.size());
    }

    public static void SetRemove(){
        Set<String> strSet = new TreeSet<String>();
        strSet.add("aaaa");
        strSet.add("bbbb");
        strSet.add("cccc");
        strSet.add("cccc");//重复的数据将不会再次插入
        strSet.add("dddd");
        for(String str : strSet){
            System.out.println(str);
        }
        System.out.println("Init Set size:" + strSet.size());
        Iterator<String> it = strSet.iterator();
        while(it.hasNext()){
            String str = it.next();
            if(str.equals("cccc")){
                it.remove();
            }
        }
        for(String str : strSet){
            System.out.println(str);
        }
        System.out.println("removed Set size:" + strSet.size());
    }

    public static void MapRemove(){
        Map<String, String> strMap = new TreeMap<String, String>();
        strMap.put("a", "aaaa");
        strMap.put("b", "bbbb");
        strMap.put("c", "cccc");
        strMap.put("d", "dddd");
        for(String key : strMap.keySet()){
            System.out.println(key + " : " + strMap.get(key));
        }
        System.out.println("Init Map size:" + strMap.size());
        Iterator<Entry<String,String>> it = strMap.entrySet().iterator();
        while(it.hasNext()){
            Entry<String,String> strEntry = it.next();
            if(strEntry.getKey().equals("c")){
                it.remove();
            }
        }
        for(String key : strMap.keySet()){
            System.out.println(key + " : " + strMap.get(key));
        }
        System.out.println("removed Map size:" + strMap.size());
    }
}

Java遍历时删除List、Set、Map中的元素(源码分析)的更多相关文章

  1. BIZ中model.getSql源码分析

    功能:根据model.xml文件中配置的sql,获取对应的动态sql结果. 实例代码:String sql1 = model.getSql(dao.dbMeta());String sql2 = mo ...

  2. Spring中Bean命名源码分析

    Spring中Bean命名源码分析 一.案例代码 首先是demo的整体结构 其次是各个部分的代码,代码本身比较简单,不是我们关注的重点 配置类 /** * @Author Helius * @Crea ...

  3. HashSet 添加/遍历元素源码分析

    HashSet 类图 HashSet 简单说明 HashSet 实现了 Set 接口 HashSet 底层实际上是由 HashMap 实现的 public HashSet() { map = new ...

  4. Java并发编程笔记之Unsafe类和LockSupport类源码分析

    一.Unsafe类的源码分析 JDK的rt.jar包中的Unsafe类提供了硬件级别的原子操作,Unsafe里面的方法都是native方法,通过使用JNI的方式来访问本地C++实现库. rt.jar ...

  5. 【朝花夕拾】Android自定义View篇之(六)Android事件分发机制(中)从源码分析事件分发逻辑及经常遇到的一些“诡异”现象

    前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/11039252.html]谢谢! 在上一篇文章[[朝花夕拾]Android自定义View篇之(五 ...

  6. Netty中的ChannelPipeline源码分析

    ChannelPipeline在Netty中是用来处理请求的责任链,默认实现是DefaultChannelPipeline,其构造方法如下: private final Channel channel ...

  7. Springboot中注解@Configuration源码分析

    Springboot中注解@Configuration和@Component的区别 1.先说结论,@Configuration注解上面有@Component注解,所以@Component有的功能@Co ...

  8. java 集合与数组的互转方法,与源码分析

    前言 java数组与集合需要互相转换的场景非常多,但是运用不好还是容易抛出UnSupportedOperationException.下面讲解一下互转的方法,以及结合源码分异常产生的原因 集合转数组 ...

  9. MapReduce中map并行度优化及源码分析

    mapTask并行度的决定机制 一个job的map阶段并行度由客户端在提交job时决定,而客户端对map阶段并行度的规划的基本逻辑为:将待处理数据执行逻辑切片(即按照一个特定切片大小,将待处理数据划分 ...

随机推荐

  1. [SDOI2009]学校食堂Dining

    题目描述 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数 ...

  2. ●BZOJ 3527 [Zjoi2014]力

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3527 题解: FFT求卷积. $$\begin{aligned}E_i&=\frac ...

  3. 【网络流】【BZOJ1006】【SCOI2007】蜥蜴

    学弟@lher在周末训练赛中出的题目的原题(这个人拿省选题来当作提高组模拟,太丧了...) 题意简析:看题目:) 解题思路:题目显然是最大流. 首先拆点将点权变为边权,然后按照题意对于所有有跳板的点向 ...

  4. bzoj4710: [Jsoi2011]分特产 组合+容斥

    4710: [Jsoi2011]分特产 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 289  Solved: 198[Submit][Status] ...

  5. BZOJ4589 Hard Nim(快速沃尔什变换模板)

    终于抽出时间来学了学,比FFT不知道好写到哪里去. #include <cstdio> typedef long long ll; ,p=1e9+; int k,m,n,a[N],pi[N ...

  6. BZOJ1187 [HNOI2007]神奇游乐园(插头dp)

    麻麻我会写插头dp了! 推荐陈丹琦论文:https://wenku.baidu.com/view/3e90d32b453610661ed9f4bd.html 破题调一年 #include <cs ...

  7. Python中byte与str

    原文传送门:请点击 现在计算机中,在内存中采用unicode编码方式. 可以看到上图中,字节型数据t并没有像想象中的一样显示0,1字符串.显示仍然是b,这是因为t是采用utf-8来编码,而utf-8与 ...

  8. Linux学习之CentOS(十七)-----释放 Linux 系统预留的硬盘空间 与Linux磁盘空间被未知资源耗尽 (转)

    释放 Linux 系统预留的硬盘空间  大多数文件系统都会保留一部分空间留作紧急情况时用(比如硬盘空间满了),这样能保证有些关键应用(比如数据库)在硬盘满的时候有点余地,不致于马上就 crash,给监 ...

  9. IOS charles抓包HTTP

    charles通常用来截取本地的网络封包,但也可以用它来截取其他设备上的网络请求.本篇以IOS为例,讲解如何进行相应的操作. 1.charles上的设置 要截取iphone上的网络请求,我们要先将ch ...

  10. Kibana插件sentinl使用教程

    简介 对于Kibana的一些数据我们有时候是想要对某些字段进行持续关注的,这时候通过报警的手段就可以大幅提升对这些信息状态了解的及时性及可靠性.使用sentinl插件就可以帮助我们实现这个功能. 此教 ...