由于很久没有进行javase的语法学习,对于HashMap中的键值对操作有些不熟悉,使用ai帮我重温了一下,于是便有了这篇博客
📚 目录(点击跳转对应章节)
- 一、最推荐:遍历
entrySet(同时获取键 + 值,效率最高)- 1. 增强 for 循环(JDK 5+,简洁易读)
- 2. 迭代器(JDK 5+,显式控制遍历流程)
- 二、仅遍历键(keySet)或仅遍历值(values)
- 1. 仅遍历键(keySet)
- 2. 仅遍历值(values)
- 三、JDK 8+ 简化写法:forEach 方法(Lambda 表达式)
- 1. 同时遍历键 + 值(推荐)
- 2. 仅遍历键/值(结合 Stream)
- 四、各遍历方式对比(选型参考)
- 五、注意事项
- 总结
在 Java 中遍历哈希表(核心实现为HashMap)的键和值,有多种方式,适配不同的 JDK 版本和使用场景(如仅遍历键、仅遍历值、同时遍历键值对)。下面按常用程度 + 易用性排序,讲解每种遍历方式的写法、适用场景和注意事项。
核心前提
HashMap实现了Map接口,遍历的核心是利用Map提供的三类视图:
keySet():获取所有键的Set集合;values():获取所有值的Collection集合;entrySet():获取所有键值对(Map.Entry)的Set集合(最推荐的全量遍历方式)。
一、最推荐:遍历entrySet(同时获取键 + 值,效率最高)
entrySet()直接返回键值对的集合,只需一次遍历即可同时获取key和value,避免了“先遍历键,再通过get(key)查值”的二次哈希查找,效率最优,是全量遍历键值对的首选。
1. 增强 for 循环(JDK 5+,简洁易读)
importjava.util.HashMap;importjava.util.Map;publicclassMapTraversal{publicstaticvoidmain(String[]args){HashMap<String,Integer>scoreMap=newHashMap<>();scoreMap.put("张三",90);scoreMap.put("李四",85);scoreMap.put("王五",95);// 遍历 entrySet,同时获取 key 和 valuefor(Map.Entry<String,Integer>entry:scoreMap.entrySet()){Stringkey=entry.getKey();// 获取键Integervalue=entry.getValue();// 获取值System.out.println("键:"+key+",值:"+value);}}}输出:
键:张三,值:90 键:李四,值:85 键:王五,值:952. 迭代器(Iterator)遍历(支持删除元素)
若遍历过程中需要安全删除元素(避免ConcurrentModificationException),需用迭代器:
importjava.util.HashMap;importjava.util.Iterator;importjava.util.Map;publicclassMapTraversal{publicstaticvoidmain(String[]args){HashMap<String,Integer>scoreMap=newHashMap<>();scoreMap.put("张三",90);scoreMap.put("李四",85);scoreMap.put("王五",95);// 迭代器遍历 entrySetIterator<Map.Entry<String,Integer>>iterator=scoreMap.entrySet().iterator();while(iterator.hasNext()){Map.Entry<String,Integer>entry=iterator.next();Stringkey=entry.getKey();Integervalue=entry.getValue();// 示例:删除值 < 90 的键值对if(value<90){iterator.remove();// 安全删除continue;}System.out.println("键:"+key+",值:"+value);}System.out.println("删除后的哈希表:"+scoreMap);// {张三=90, 王五=95}}}二、仅遍历键(keySet)或仅遍历值(values)
若只需单独处理键或值,无需同时获取,用keySet()或values()更简洁。
1. 仅遍历键(keySet)
HashMap<String,Integer>scoreMap=newHashMap<>();scoreMap.put("张三",90);scoreMap.put("李四",85);// 增强 for 循环遍历键for(Stringkey:scoreMap.keySet()){System.out.println("键:"+key);}// 迭代器遍历键(支持删除)Iterator<String>keyIterator=scoreMap.keySet().iterator();while(keyIterator.hasNext()){Stringkey=keyIterator.next();if(key.equals("李四")){keyIterator.remove();// 删除键,对应的键值对也会被删除}}2. 仅遍历值(values)
HashMap<String,Integer>scoreMap=newHashMap<>();scoreMap.put("张三",90);scoreMap.put("李四",85);// 增强 for 循环遍历值for(Integervalue:scoreMap.values()){System.out.println("值:"+value);}// 迭代器遍历值(注意:无法直接通过值删除键值对)Iterator<Integer>valueIterator=scoreMap.values().iterator();while(valueIterator.hasNext()){Integervalue=valueIterator.next();if(value==85){// 错误示例:valueIterator.remove() 会导致异常或不一致// 正确做法:建议改用 entrySet 迭代器通过键删除}}三、JDK 8+ 简化写法:forEach 方法(Lambda 表达式)
JDK 8 新增的forEach方法(Map接口默认方法),用 Lambda 表达式简化遍历,代码最简洁。
1. 同时遍历键 + 值(推荐)
HashMap<String,Integer>scoreMap=newHashMap<>();scoreMap.put("张三",90);scoreMap.put("李四",85);// forEach + Lambda 遍历键值对scoreMap.forEach((key,value)->{System.out.println("键:"+key+",值:"+value);// 支持修改值(需重新 put)if(key.equals("张三")){scoreMap.put(key,value+5);// 张三的分数改为 95}});System.out.println("修改后的哈希表:"+scoreMap);// {张三=95, 李四=85}2. 仅遍历键/值(结合 Stream)
// 仅遍历键(stream 过滤)scoreMap.keySet().stream().filter(key->key.startsWith("张")).forEach(key->System.out.println("过滤后的键:"+key));// 仅遍历值(stream 求和)inttotalScore=scoreMap.values().stream().mapToInt(Integer::intValue).sum();System.out.println("总分:"+totalScore);// 示例:180四、各遍历方式对比(选型参考)
| 遍历方式 | 适用场景 | 效率 | 支持删除 | JDK 版本 |
|---|---|---|---|---|
| entrySet(增强 for) | 同时遍历键+值,无需删除 | 最高 | 不支持 | 5+ |
| entrySet(迭代器) | 同时遍历键+值,需删除元素 | 最高 | 支持 | 1.2+ |
| keySet | 仅遍历键,或通过键查值 | 较低(二次哈希) | 支持 | 1.2+ |
| values | 仅遍历值 | 中等 | 不推荐 | 1.2+ |
| forEach(Lambda) | 简洁遍历,无需复杂逻辑 | 同 entrySet | 不支持(需手动 put/remove) | 8+ |
五、注意事项
- 无序性:
HashMap遍历顺序不保证与插入顺序一致,若需保留插入顺序,使用LinkedHashMap(遍历方式完全相同); - 线程安全:非线程安全的
HashMap在多线程遍历/修改时,需加锁(如synchronized)或使用ConcurrentHashMap; - 禁止遍历中修改:增强 for 循环遍历中直接
put/remove会抛出ConcurrentModificationException,需用迭代器或ConcurrentHashMap; - 自定义对象作为键:若键是自定义对象,需重写
hashCode()和equals(),否则遍历可能出现异常(如重复键)。
总结
- 优先选:
entrySet(增强 for / 迭代器)→ 效率最高,支持同时获取键值对; - JDK 8+ 首选:
forEach(Lambda)→ 代码最简洁; - 仅需键/值:
keySet()/values()→ 简化代码; - 需删除元素:
entrySet迭代器 → 安全无异常。