公司新来一个同事:为什么 HashMap 不能一边遍历一边删除?一下子把我问懵了!(1)

简介: 公司新来一个同事:为什么 HashMap 不能一边遍历一边删除?一下子把我问懵了!

作者:你呀不牛

链接:https://juejin.cn/post/7114669787870920734

前段时间,同事在代码中KW扫描的时候出现这样一条:

image.png


上面出现这样的原因是在使用foreach对HashMap进行遍历时,同时进行put赋值操作会有问题,异常ConcurrentModificationException。


于是帮同简单的看了一下,印象中集合类在进行遍历时同时进行删除或者添加操作时需要谨慎,一般使用迭代器进行操作。


于是告诉同事,应该使用迭代器Iterator来对集合元素进行操作。同事问我为什么?这一下子把我问蒙了?对啊,只是记得这样用不可以,但是好像自己从来没有细究过为什么?


于是今天决定把这个HashMap遍历操作好好地研究一番,防止采坑!


foreach循环?

java foreach 语法是在jdk1.5时加入的新特性,主要是当作for语法的一个增强,那么它的底层到底是怎么实现的呢?下面我们来好好研究一下:


foreach 语法内部,对collection是用iterator迭代器来实现的,对数组是用下标遍历来实现。Java 5 及以上的编译器隐藏了基于iteration和数组下标遍历的内部实现。


(注意,这里说的是“Java编译器”或Java语言对其实现做了隐藏,而不是某段Java代码对其实现做了隐藏,也就是说,我们在任何一段JDK的Java代码中都找不到这里被隐藏的实现。这里的实现,隐藏在了Java 编译器中,查看一段foreach的Java代码编译成的字节码,从中揣测它到底是怎么实现的了)


我们写一个例子来研究一下:


public class HashMapIteratorDemo {
    String[] arr = {"aa", "bb", "cc"};
    public void test1() {
        for(String str : arr) {
        }
    }
}



将上面的例子转为字节码反编译一下(主函数部分):


image.png


也许我们不能很清楚这些指令到底有什么作用,但是我们可以对比一下下面段代码产生的字节码指令:


public class HashMapIteratorDemo2 {
    String[] arr = {"aa", "bb", "cc"};
    public void test1() {
        for(int i = 0; i < arr.length; i++) {
            String str = arr[i];
        }
    }
}


image.png


看看两个字节码文件,有木有发现指令几乎相同,如果还有疑问我们再看看对集合的foreach操作:


通过foreach遍历集合:


public class HashMapIteratorDemo3 {
    List<Integer> list = new ArrayList<>();
    public void test1() {
        list.add(1);
        list.add(2);
        list.add(3);
        for(Integer var : list) {
        }
    }
}


通过Iterator遍历集合:


public class HashMapIteratorDemo4 {
    List<Integer> list = new ArrayList<>();
    public void test1() {
        list.add(1);
        list.add(2);
        list.add(3);
        Iterator<Integer> it = list.iterator();
        while(it.hasNext()) {
            Integer var = it.next();
        }
    }
}


将两个方法的字节码对比如下:


image.png



image.png




我们发现两个方法字节码指令操作几乎一模一样;


这样我们可以得出以下结论:


对集合来说,由于集合都实现了Iterator迭代器,foreach语法最终被编译器转为了对Iterator.next()的调用;


对于数组来说,就是转化为对数组中的每一个元素的循环引用。



相关文章
|
8月前
HashMap遍历方式
HashMap遍历方式
|
9月前
|
安全 Java API
java中HashMap的七种遍历方式
java.util.ConcurrentModificationException , 这种办法是非安全的 , 我们可以使用Iterator.remove() ,或者是Lambda 中的 removeIf() , 或者是Stream 中的 filter() 过滤或者删除相关数据
66 1
|
2月前
|
Java API
面试官上来就让手撕HashMap的7种遍历方式,当场愣住,最后只写出了3种
面试官上来就让手撕HashMap的7种遍历方式,当场愣住,最后只写出了3种
26 1
|
12月前
|
存储 算法 安全
HashMap的遍历方式及底层原理
HashMap的遍历方式及底层原理
遍历HashMap的四种方式
遍历HashMap的四种方式
59 0
|
Java API
公司新来一个同事:为什么 HashMap 不能一边遍历一边删除?一下子把我问懵了!(2)
公司新来一个同事:为什么 HashMap 不能一边遍历一边删除?一下子把我问懵了!
172 0
公司新来一个同事:为什么 HashMap 不能一边遍历一边删除?一下子把我问懵了!(2)
|
JavaScript 小程序 Java
HashMap 为什么不能一边遍历一遍删除
HashMap 为什么不能一边遍历一遍删除
|
Java
Java:遍历HashMap的常用方法
Java:遍历HashMap的常用方法
122 0
|
Java
【Java系列】HashMap的6种遍历方法
通过对map entrySet的遍历,也可以同时拿到key和value,一般情况下,性能上要优于上一种,这一种也是最常用的遍历方法。
183 0
【Java系列】HashMap的6种遍历方法
|
2月前
|
存储 算法 Java
【深入挖掘Java技术】「源码原理体系」盲点问题解析之HashMap工作原理全揭秘(下)
在阅读了上篇文章《【深入挖掘Java技术】「源码原理体系」盲点问题解析之HashMap工作原理全揭秘(上)》之后,相信您对HashMap的基本原理和基础结构已经有了初步的认识。接下来,我们将进一步深入探索HashMap的源码,揭示其深层次的技术细节。通过这次解析,您将更深入地理解HashMap的工作原理,掌握其核心实现。
36 0
【深入挖掘Java技术】「源码原理体系」盲点问题解析之HashMap工作原理全揭秘(下)