Java HashMap在遍历时删除元素

2023-12-24 18:20

本文主要是介绍Java HashMap在遍历时删除元素,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1. HashMap数据结构
    • 1.1 数组+单向链表+红黑树
    • 1.2 指定初始容量,省去多次扩容步骤
    • 1.3 获取map内容:Map.Entry
  • 2. 遍历集合时删除元素
  • 3. computeIfAbsent()方法

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<Integer, String> stuMap = new HashMap<>();stuMap.put(1, "xlsj");stuMap.put(2, "xinliushijian");stuMap.put(3, "心流时间");// A: entrySet()、keySet()、values()方法作用// key:value 集合Set<Map.Entry<Integer, String>> stuEntrySet = stuMap.entrySet();// key 集合Set<Integer> stuKeySet = stuMap.keySet();// value 集合Collection<String> 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<K,V> nextNode() {HashMap.Node<K,V>[] t;HashMap.Node<K,V> e = next;if (modCount != expectedModCount)throw new ConcurrentModificationException();if (e == null)throw new NoSuchElementException();if ((next = (current = e).next) == null && (t = table) != null) {do {} while (index < t.length && (next = t[index++]) == null);}return e;}*/// 1.普通for循环遍历时可以删除元素for (int i = 0; i < stuKeySet.size(); i++) {if (i == 2) {stuKeySet.remove(i);}}// 2.for增强循环遍历时删除元素报异常:Exception in thread "main" java.util.ConcurrentModificationExceptionfor (int i : stuKeySet) {if (i == 2) {stuKeySet.remove(i);}}// 3.forEach循环遍历时删除元素报异常:Exception in thread "main" java.util.ConcurrentModificationExceptionstuMap.forEach((k, v) -> {if (k == 2) {stuKeySet.remove(k);}});// 4.stream forEach循环遍历时删除元素报异常:Exception in thread "main" java.util.ConcurrentModificationExceptionstuKeySet.stream().forEach(k -> {if (k == 2) {stuKeySet.remove(k);}});// 5.迭代器遍历时可以删除元素Iterator integers = stuEntrySet.iterator();while (integers.hasNext()) {Map.Entry<Integer, String> entry = (Map.Entry<Integer, String>) 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"));}

这篇关于Java HashMap在遍历时删除元素的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/532694

相关文章

Java NoClassDefFoundError运行时错误分析解决

《JavaNoClassDefFoundError运行时错误分析解决》在Java开发中,NoClassDefFoundError是一种常见的运行时错误,它通常表明Java虚拟机在尝试加载一个类时未能... 目录前言一、问题分析二、报错原因三、解决思路检查类路径配置检查依赖库检查类文件调试类加载器问题四、常见

Java注解之超越Javadoc的元数据利器详解

《Java注解之超越Javadoc的元数据利器详解》本文将深入探讨Java注解的定义、类型、内置注解、自定义注解、保留策略、实际应用场景及最佳实践,无论是初学者还是资深开发者,都能通过本文了解如何利用... 目录什么是注解?注解的类型内置注编程解自定义注解注解的保留策略实际用例最佳实践总结在 Java 编程

Java 实用工具类Spring 的 AnnotationUtils详解

《Java实用工具类Spring的AnnotationUtils详解》Spring框架提供了一个强大的注解工具类org.springframework.core.annotation.Annot... 目录前言一、AnnotationUtils 的常用方法二、常见应用场景三、与 JDK 原生注解 API 的

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

Java中的StringBuilder之如何高效构建字符串

《Java中的StringBuilder之如何高效构建字符串》本文将深入浅出地介绍StringBuilder的使用方法、性能优势以及相关字符串处理技术,结合代码示例帮助读者更好地理解和应用,希望对大家... 目录关键点什么是 StringBuilder?为什么需要 StringBuilder?如何使用 St

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B