Java HashMap在遍历时删除元素的实现

 更新时间:2023年12月25日 15:11:38   作者:心流时间  
本文主要介绍了Java HashMap在遍历时删除元素的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1. HashMap数据结构

jdk是1.8版本

HashMap 线程不安全
ConcurrentHashMap 线程安全

1.1 数组+单向链表+红黑树

元素放入hashmap中,放入node节点中,nodel节点有四个字段key value next hash,当两个元素的key通过hash算法得到的hash值相同时就会存入单向链表中。hashmap初始值是16,负载因子是0.75,得到阈值是12,当元素超过12就会扩容,当数组长度超过64并且单向链表长度超过8就会将单向链表转为红黑树,当红黑树数据量小于6就会再转为单向链表

jdk1.8 之前 HashMap 由 数组 + 链表 组成,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突(两个对象调用的 hashCode 方法计算的哈希值经哈希函数算出来的地址被别的元素占用)而存在的(“拉链法”解决冲突)。jdk1.8 以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(或者红黑树的边界值,默认为 8 )并且当前数组的长度大于 64 时,此时此索引位置上的所有数据改为使用红黑树存储。

在这里插入图片描述

1.2 指定初始容量,省去多次扩容步骤

实际工作中对HashMap数据结构的关注点,我们可以放在扩容上;
HashMap初始容量是16,当大于这个值,就会扩容,每次都是扩大成原来的两倍;
所以,如果我们可以估算出我们的map需要多大的容量,在初始化的时候直接指定初始容量值,这样就省略了HashMap一次次扩容的步骤

1.3 获取map内容:Map.Entry

Map.Entry是Java中Map接口的一个内部接口,用于表示Map中的一个实体,即一个键值对(key-value对)。它是一个泛型接口,定义为Entry<K,V>,其中K表示键的类型,V表示值的类型。

你可以使用Map.Entry来遍历Map集合,并获取每个键值对的键和值。下面是一个示例代码:

import java.util.HashMap;
import java.util.Map;

public class MapEntryExample {
    public static void main(String[] args) {
        Map<Integer, String> maps = new HashMap<>();
        maps.put(3, "张飞");
        maps.put(2, "关羽");
        maps.put(4, "赵云");
        maps.put(1, "刘备");
        maps.put(5, "马超");

        for (Map.Entry<Integer, String> entry : maps.entrySet()) {
            System.out.println("key=" + entry.getKey() + " value=" + entry.getValue());
        }
    }
}
这段代码会输出Map中每个键值对的键和值:

key=1 value=刘备
key=2 value=关羽
key=3 value=张飞
key=4 value=赵云
key=5 value=马超
通过使用Map.Entry,你可以方便地遍历Map集合并获取每个键值对的键和值。

2. 遍历集合时删除元素

遍历集合时删除元素这种场景建议用迭代器处理 或者 再新建一个集合进行存储

    public static void main(String[] args) {
        Map&lt;Integer, String&gt; stuMap = new HashMap&lt;&gt;();
        stuMap.put(1, "xlsj");
        stuMap.put(2, "xinliushijian");
        stuMap.put(3, "心流时间");

        // A: entrySet()、keySet()、values()方法作用
        // key:value 集合
        Set&lt;Map.Entry&lt;Integer, String&gt;&gt; stuEntrySet = stuMap.entrySet();
        // key 集合
        Set&lt;Integer&gt; stuKeySet = stuMap.keySet();
        // value 集合
        Collection&lt;String&gt; stuValues = stuMap.values();

        System.out.println(stuEntrySet); // [1=xlsj, 2=xinliushijian, 3=心流时间]
        System.out.println(stuKeySet); // [1, 2, 3]
        System.out.println(stuValues); // [xlsj, xinliushijian, 心流时间]


        // B: 遍历集合时删除元素, 普通for循环、迭代器不会报错,其他会报错,增强for循环其实也是用到迭代器,
        // 集合遍历时不可以删除元素,而迭代器可以
        // 报错原因如下modCount != expectedModCount
/*        final HashMap.Node&lt;K,V&gt; nextNode() {
            HashMap.Node&lt;K,V&gt;[] t;
            HashMap.Node&lt;K,V&gt; e = next;
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            if (e == null)
                throw new NoSuchElementException();
            if ((next = (current = e).next) == null &amp;&amp; (t = table) != null) {
                do {} while (index &lt; t.length &amp;&amp; (next = t[index++]) == null);
            }
            return e;
        }*/
        

        // 1.普通for循环遍历时可以删除元素
        for (int i = 0; i &lt; stuKeySet.size(); i++) {
            if (i == 2) {
                stuKeySet.remove(i);
            }
        }

        // 2.for增强循环遍历时删除元素报异常:Exception in thread "main" java.util.ConcurrentModificationException
        for (int i : stuKeySet) {
            if (i == 2) {
                stuKeySet.remove(i);
            }
        }

        // 3.forEach循环遍历时删除元素报异常:Exception in thread "main" java.util.ConcurrentModificationException
        stuMap.forEach((k, v) -&gt; {
            if (k == 2) {
                stuKeySet.remove(k);
            }
        });

        // 4.stream forEach循环遍历时删除元素报异常:Exception in thread "main" java.util.ConcurrentModificationException
        stuKeySet.stream().forEach(k -&gt; {
            if (k == 2) {
                stuKeySet.remove(k);
            }
        });

        // 5.迭代器遍历时可以删除元素
        Iterator integers = stuEntrySet.iterator();
        while (integers.hasNext()) {
            Map.Entry&lt;Integer, String&gt; entry = (Map.Entry&lt;Integer, String&gt;) integers.next();
            System.out.println(entry.getKey());
            if (entry.getKey() == 2) {
                integers.remove();
            }

        }

        System.out.println(stuMap);
    }

3. computeIfAbsent()方法

key不存在或者value为null时,使用put给定的值

    public static void main(String[] args) {
        Map<String, List<String>> map = new HashMap<>();
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        map.put("xin", list);
        map.put("xi", new ArrayList<>());
        map.put("x", null);

        // jing这个key不存在或者对应的value不存在,则put给的值
        List<String> list1 = map.computeIfAbsent("jing",h -> Arrays.asList(new String[]{"DE", "BU", "DE"}));
        List<String> list2 = map.computeIfAbsent("xin",h -> Arrays.asList(new String[]{"DE", "BU", "DE"}));
        List<String> list3 = map.computeIfAbsent("xi",h -> Arrays.asList(new String[]{"DE", "BU", "DE"}));
        List<String> list4 = map.computeIfAbsent("x",h -> Arrays.asList(new String[]{"DE", "BU", "DE"}));
        System.out.println(list1);
        System.out.println(list2);
        System.out.println(list3);
        System.out.println(list4);
        System.out.println("---------------jing--------------");
        System.out.println(map.get("jing"));

        map.putIfAbsent("jing1", Arrays.asList(new String[]{"DE1", "BU1", "DE1"}));
        System.out.println("---------------jing1--------------");
        System.out.println(map.get("jing1"));
    }

打印

[DE, BU, DE]
[a, b, c]
[]
[DE, BU, DE]
---------------jing--------------
[DE, BU, DE]
---------------jing1--------------
[DE1, BU1, DE1]

到此这篇关于Java HashMap在遍历时删除元素的实现的文章就介绍到这了,更多相关Java HashMap遍历时删除元素内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

相关文章

  • jdk1.8中的for循环问题记录

    jdk1.8中的for循环问题记录

    这篇文章主要介绍了jdk1.8中的for循环及jdk1.8 新特性之 forEach 循环遍历问题,本文通过实例代码给大家详细讲解,需要的朋友可以参考下
    2022-11-11
  • java实现两个文件的拼接

    java实现两个文件的拼接

    这篇文章主要为大家详细介绍了java实现两个文件的拼接,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • Java中的Map允许有重复元素吗?

    Java中的Map允许有重复元素吗?

    今天小编就为大家分享一篇关于Java中的Map允许有重复元素吗?,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • java与php的区别浅析

    java与php的区别浅析

    在本篇文章里小编给大家整理了关于java与php的区别以及相关知识点,有兴趣的朋友们学习下。
    2019-03-03
  • Eclipse智能提示及快捷键

    Eclipse智能提示及快捷键

    本文主要介绍了Eclipse智能提示及快捷键的相关知识,具有很好的参考价值。下面跟着小编一起来看下吧
    2017-03-03
  • java基于递归算法实现汉诺塔问题实例

    java基于递归算法实现汉诺塔问题实例

    这篇文章主要介绍了java基于递归算法实现汉诺塔问题,结合具体实例形式分析了java递归算法的实现与使用技巧,需要的朋友可以参考下
    2017-07-07
  • 一文带你深入了解Java中延时任务的实现

    一文带你深入了解Java中延时任务的实现

    延时任务相信大家都不陌生,在现实的业务中应用场景可以说是比比皆是。这篇文章主要为大家介绍几种实现延时任务的办法,感兴趣的可以了解一下
    2022-11-11
  • Spring Boot循环依赖的症状和解决方案

    Spring Boot循环依赖的症状和解决方案

    循环依赖是指在Spring Boot 应用程序中,两个或多个类之间存在彼此依赖的情况,形成一个循环依赖链。这篇文章主要介绍了SpringBoot循环依赖的症状和解决方法
    2023-04-04
  • 使用java实现各种数据统计图(柱形图,饼图,折线图)

    使用java实现各种数据统计图(柱形图,饼图,折线图)

    用Jfree实现条形柱状图表,java代码实现。可经常用于报表的制作,代码自动生成后可以自由查看。可以自由配置图表的各个属性,用来达到自己的要求和目的。本文给大家介绍使用java实现各种数据统计图(柱形图,饼图,折线图),需要的朋友可以参考下
    2015-10-10
  • Java通过Lambda表达式实现简化代码

    Java通过Lambda表达式实现简化代码

    我们在编写代码时,常常会遇到代码又长又重复的情况,就像调用第3方服务时,每个方法都差不多, 写起来啰嗦, 改起来麻烦, 还容易改漏,所以本文就来用Lambda表达式简化一下代码,希望对大家有所帮助
    2023-05-05

最新评论