Java 实例 – HashMap遍历(一文讲透)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
前言
在 Java 开发中,HashMap 是一个高频使用的数据结构,它通过键值对(Key-Value)实现高效的数据存储与检索。然而,当需要遍历 HashMap 中的所有元素时,开发者常会面临多种遍历方式的选择,以及潜在的线程安全或性能问题。本文将以“Java 实例 – HashMap遍历”为核心,从基础概念到实战案例,系统性地讲解如何高效、安全地遍历 HashMap,并解答常见疑问。无论是编程初学者还是中级开发者,都能从中获得实用的技术洞察。
一、HashMap 的基础概念与存储原理
1.1 HashMap 的核心特性
HashMap 是 Java 集合框架中基于哈希表实现的 Key-Value 存储结构,其核心特性包括:
- 键唯一性:每个键(Key)必须是唯一的,值(Value)可以重复。
- 无序性:元素存储顺序不依赖插入顺序,而是由哈希算法决定。
- 允许 null 值:可以存储一个
null
键和多个null
值。
形象比喻:
可以将 HashMap 想象为一个“智能仓库”,每个物品(Value)都被分配一个独一无二的储物柜编号(Key)。当需要查找物品时,只需通过编号快速定位,而非逐个翻找。
1.2 哈希表的工作原理
HashMap 的底层通过哈希表实现,其核心步骤如下:
- 哈希计算:通过
hashCode()
方法计算键的哈希值。 - 索引定位:将哈希值与表长取模,确定键值对在数组中的存储位置。
- 链表或红黑树处理冲突:当哈希冲突(不同键的哈希值相同)发生时,使用链表或红黑树(当链表长度超过阈值时)存储冲突元素。
二、HashMap 的遍历方法详解
遍历 HashMap 的核心目标是访问所有键、值或键值对。根据不同的需求,Java 提供了多种遍历方式,以下将逐一讲解。
2.1 使用迭代器(Iterator)遍历
迭代器 是一种面向对象的遍历工具,通过 keySet()
或 entrySet()
方法配合 Iterator
实现。
2.1.1 遍历键集合(Key)
HashMap<String, Integer> map = new HashMap<>();
map.put("Apple", 1);
map.put("Banana", 2);
Iterator<String> keyIterator = map.keySet().iterator();
while (keyIterator.hasNext()) {
String key = keyIterator.next();
System.out.println("Key: " + key);
}
关键点:通过 keySet()
获取所有键的集合,再通过迭代器逐个访问键。
2.1.2 遍历键值对(Entry)
Iterator<Map.Entry<String, Integer>> entryIterator = map.entrySet().iterator();
while (entryIterator.hasNext()) {
Map.Entry<String, Integer> entry = entryIterator.next();
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
优势:直接访问键值对,适合需要同时操作键和值的场景。
2.2 使用增强 for 循环(for-each)
增强 for 循环 是 Java 5 引入的简化语法,适用于遍历集合或数组。
2.2.1 遍历键集合
for (String key : map.keySet()) {
System.out.println("Key: " + key);
}
2.2.2 遍历值集合
for (Integer value : map.values()) {
System.out.println("Value: " + value);
}
2.2.3 遍历键值对
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
注意:增强 for 循环本质上是对迭代器的封装,因此同样支持安全删除元素(通过迭代器的 remove()
方法)。
2.3 使用 Java 8 的 Lambda 表达式
Java 8 引入的 Lambda 表达式 和 Stream API 可以进一步简化代码逻辑。
map.forEach((key, value) -> {
System.out.println("Key: " + key + ", Value: " + value);
});
优势:代码简洁,适合简单的遍历和处理逻辑。
2.4 对比遍历方式的性能与适用场景
遍历方式 | 适用场景 | 性能特点 |
---|---|---|
迭代器(entrySet) | 需要同时操作键和值,或需要删除元素 | 较高,支持安全删除操作 |
增强 for 循环 | 简单遍历键或值,代码可读性高 | 中等,语法简洁 |
Lambda + Stream | 需要链式操作或并行处理 | 可能引入额外开销,适合复杂逻辑 |
三、遍历 HashMap 时的注意事项
3.1 遍历时修改 HashMap 的风险
在遍历过程中直接修改 HashMap(如添加或删除元素)会导致 ConcurrentModificationException 异常。例如:
// 错误示例:遍历过程中删除键
for (String key : map.keySet()) {
if (key.equals("Banana")) {
map.remove(key); // 抛出异常
}
}
解决方案:
- 使用迭代器的
remove()
方法:Iterator<String> iterator = map.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); if (key.equals("Banana")) { iterator.remove(); // 安全删除 } }
- 在遍历前创建临时集合,避免直接修改原 Map:
List<String> keysToRemove = new ArrayList<>(); for (String key : map.keySet()) { if (key.equals("Banana")) { keysToRemove.add(key); } } map.keySet().removeAll(keysToRemove);
3.2 线程安全问题
HashMap 是非线程安全的,若在多线程环境下遍历,可能因其他线程修改数据而引发异常。此时可考虑使用 ConcurrentHashMap 替代。
四、实战案例:用户管理系统
4.1 需求背景
假设需要实现一个用户管理系统,存储用户 ID(String)与年龄(Integer),并支持以下操作:
- 遍历所有用户并输出信息。
- 删除年龄小于 18 岁的用户。
4.2 完整代码示例
import java.util.*;
public class UserManager {
private HashMap<String, Integer> userMap = new HashMap<>();
public void addUser(String id, Integer age) {
userMap.put(id, age);
}
// 使用 entrySet 迭代器遍历并删除
public void removeMinors() {
Iterator<Map.Entry<String, Integer>> iterator = userMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Integer> entry = iterator.next();
if (entry.getValue() < 18) {
iterator.remove();
}
}
}
// 使用 Lambda 表达式遍历输出
public void printAllUsers() {
userMap.forEach((id, age) -> {
System.out.println("User ID: " + id + ", Age: " + age);
});
}
public static void main(String[] args) {
UserManager userManager = new UserManager();
userManager.addUser("U001", 25);
userManager.addUser("U002", 16);
userManager.addUser("U003", 30);
System.out.println("Before removal:");
userManager.printAllUsers();
userManager.removeMinors();
System.out.println("\nAfter removal:");
userManager.printAllUsers();
}
}
4.3 运行结果
Before removal:
User ID: U001, Age: 25
User ID: U002, Age: 16
User ID: U003, Age: 30
After removal:
User ID: U001, Age: 25
User ID: U003, Age: 30
五、结论
通过本文的讲解,开发者应掌握以下核心要点:
- HashMap 的遍历方法:迭代器、增强 for 循环、Lambda 表达式各有适用场景,需根据需求选择。
- 安全操作原则:遍历时修改 Map 必须通过迭代器的
remove()
方法,或使用临时集合规避异常。 - 性能与线程安全:在高并发场景下,优先使用 ConcurrentHashMap 替代普通 HashMap。
Java 实例 – HashMap遍历 是开发中的高频操作,深入理解其原理与最佳实践,不仅能提升代码质量,还能为复杂场景(如分布式系统或大数据处理)打下坚实基础。建议读者通过本文提供的代码示例,动手实践并探索更多进阶用法。