面试官:HashMap有几种遍历方法?推荐使用哪种?

87d6b391b6341559c81fd9614ebc120b.png

作者 | 磊哥

来源 | Java面试真题解析(ID:aimianshi666)

转载请联系授权(微信ID:GG_Stone)

HashMap 的遍历方法有很多种,不同的 JDK 版本有不同的写法,其中 JDK 8 就提供了 3 种 HashMap 的遍历方法,并且一举打破了之前遍历方法“很臃肿”的尴尬。

1.JDK 8 之前的遍历

JDK 8 之前主要使用 EntrySet 和 KeySet 进行遍历,具体实现代码如下。

1.1 EntrySet 遍历

EntrySet 是早期 HashMap 遍历的主要方法,其实现代码如下:

public static void main(String[] args) {// 创建并赋值 hashmapHashMap<String, String> map = new HashMap() {{put("Java", " Java Value.");put("MySQL", " MySQL Value.");put("Redis", " Redis Value.");}};// 循环遍历for (Map.Entry<String, String> entry : map.entrySet()) {System.out.println(entry.getKey() + ":" + entry.getValue());}
}

以上程序的执行结果,如下图所示:0bf1fe6ea69bd475b011d6a636ad69ab.png

1.2 KeySet 遍历

KeySet 的遍历方式是循环 Key 内容,再通过 map.get(key) 获取 Value 的值,具体实现如下:

public static void main(String[] args) {// 创建并赋值 hashmapHashMap<String, String> map = new HashMap() {{put("Java", " Java Value.");put("MySQL", " MySQL Value.");put("Redis", " Redis Value.");}};// 循环遍历for (String key : map.keySet()) {System.out.println(key + ":" + map.get(key));}
}

以上程序的执行结果,如下图所示:fa646c629ebe827a743865b47369dd9e.png

KeySet 性能问题

通过以上代码,我们可以看出使用 KeySet 遍历,其性能是不如 EntrySet 的,因为 KeySet 其实循环了两遍集合,第一遍循环是循环 Key,而获取 Value 有需要使用 map.get(key),相当于有循环了一遍集合,所以 KeySet 循环不能建议使用,因为循环了两次,效率比较低

1.3 EntrySet 迭代器遍历

EntrySet 和 KeySet 除了以上直接循环外,我们还可以使用它们的迭代器进行循环,如 EntrySet 的迭代器实现代码如下:

public static void main(String[] args) {// 创建并赋值 hashmapHashMap<String, String> map = new HashMap() {{put("Java", " Java Value.");put("MySQL", " MySQL Value.");put("Redis", " Redis Value.");}};// 循环遍历Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();while (iterator.hasNext()) {Map.Entry<String, String> entry = iterator.next();System.out.println(entry.getKey() + ":" + entry.getValue());}
}

以上程序的执行结果,如下图所示:828d4b049f492a65499331c17133b6bc.png

1.4 KeySet 迭代器遍历

KeySet 也可以使用迭代器的方式进行遍历,实现代码如下:

public static void main(String[] args) {// 创建并赋值 hashmapHashMap<String, String> map = new HashMap() {{put("Java", " Java Value.");put("MySQL", " MySQL Value.");put("Redis", " Redis Value.");}};// 循环遍历Iterator<String> iterator = map.keySet().iterator();while (iterator.hasNext()) {String key = iterator.next();System.out.println(key + ":" + map.get(key));}
}

以上程序的执行结果,如下图所示:455d77eb97f279d5488a66a3e3663e7c.png虽然 KeySet 循环方式不推荐使用,但还是有必要了解一下的。

1.5 迭代器的作用

既然能直接遍历,那为什么还要用迭代器呢?通过以下例子我们就知道了。

不使用迭代器删除

如果不使用迭代器,假如我们在遍历 EntrySet 时,在遍历代码中删除元素,代码的实现如下:

public static void main(String[] args) {// 创建并赋值 hashmapHashMap<String, String> map = new HashMap() {{put("Java", " Java Value.");put("MySQL", " MySQL Value.");put("Redis", " Redis Value.");}};// 循环遍历for (Map.Entry<String, String> entry : map.entrySet()) {if ("Java".equals(entry.getKey())) {// 删除此项map.remove(entry.getKey());continue;}System.out.println(entry.getKey() + ":" + entry.getValue());}
}

以上程序的执行结果,如下图所示:e0ec09650b69e83c37cc1d8d0e6f84ee.png可以看到,如果在遍历的代码中动态删除元素,非迭代器的方式就会报错。

使用迭代器删除

接下来,我们使用迭代器循环 EntrySet,并且在循环中动态删除元素,实现代码如下:

public static void main(String[] args) {// 创建并赋值 hashmapHashMap<String, String> map = new HashMap() {{put("Java", " Java Value.");put("MySQL", " MySQL Value.");put("Redis", " Redis Value.");}};// 循环遍历Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();while (iterator.hasNext()) {Map.Entry<String, String> entry = iterator.next();if ("Java".equals(entry.getKey())) {// 删除此项iterator.remove();continue;}System.out.println(entry.getKey() + ":" + entry.getValue());}
}

以上程序的执行结果,如下图所示:f1cf4d0d2e0020a4dda70bafb176ceca.png从上述结果可以看出,使用迭代器的优点是可以在循环的时候,动态的删除集合中的元素。而上面非迭代器的方式则不能在循环的过程中删除元素(程序会报错)。

2.JDK 8 之后的遍历

在 JDK 8 之后 HashMap 的遍历就变得方便很多了,JDK 8 中包含了以下 3 种遍历方法:

  • 使用 Lambda 遍历

  • 使用 Stream 单线程遍历

  • 使用 Stream 多线程遍历

我们分别来看。

2.1 Lambda 遍历

使用 Lambda 表达式的遍历方法实现代码如下:

public static void main(String[] args) {// 创建并赋值 hashmapHashMap<String, String> map = new HashMap() {{put("Java", " Java Value.");put("MySQL", " MySQL Value.");put("Redis", " Redis Value.");}};// 循环遍历map.forEach((key, value) -> {System.out.println(key + ":" + value);});
}

以上程序的执行结果,如下图所示:5a2ad7073d57bb4507b06e82273677db.png

2.2 Stream 单线程遍历

Stream 遍历是先得到 map 集合的 EntrySet,然后再执行 forEach 循环,实现代码如下:

public static void main(String[] args) {// 创建并赋值 hashmapHashMap<String, String> map = new HashMap() {{put("Java", " Java Value.");put("MySQL", " MySQL Value.");put("Redis", " Redis Value.");}};// 循环遍历map.entrySet().stream().forEach((entry) -> {System.out.println(entry.getKey() + ":" + entry.getValue());});
}

以上程序的执行结果,如下图所示:eb2a321a2422e99cdb50872b8e703a5f.png

2.3 Stream 多线程遍历

Stream 多线程的遍历方式和上一种遍历方式类似,只是多执行了一个 parallel 并发执行的方法,此方法会根据当前的硬件配置生成对应的线程数,然后再进行遍历操作,实现代码如下:

public static void main(String[] args) {// 创建并赋值 hashmapHashMap<String, String> map = new HashMap() {{put("Java", " Java Value.");put("MySQL", " MySQL Value.");put("Redis", " Redis Value.");}};// 循环遍历map.entrySet().stream().parallel().forEach((entry) -> {System.out.println(entry.getKey() + ":" + entry.getValue());});
}

以上程序的执行结果,如下图所示:e1b9715ef28c8007dd06ca1b6181ea0c.png注意上述图片的执行结果,可以看出当前执行结果和之前的所有遍历结果都不一样(打印元素的顺序不一样),因为程序是并发执行的,所以没有办法保证元素的执行顺序和打印顺序,这就是并发编程的特点。

推荐使用哪种遍历方式?

不同的场景推荐使用的遍历方式是不同的,例如,如果是 JDK 8 之后的开发环境,推荐使用 Stream 的遍历方式,因为它足够简洁;而如果在遍历的过程中需要动态的删除元素,那么推荐使用迭代器的遍历方式;如果在遍历的时候,比较在意程序的执行效率,那么推荐使用 Stream 多线程遍历的方式,因为它足够快。所以这个问题的答案是不固定的,我们需要知道每种遍历方法的优缺点,再根据不同的场景灵活变通。

总结

本文介绍了 7 种 HashMap 的遍历方式,其中 JDK 8 之前主要使用 EntrySet 和 KeySet 的遍历方式,而 KeySet 的遍历方式性能比较低,一般不推荐使用。然而在 JDK 8 之后遍历方式就有了新的选择,可以使用比较简洁的 Lambda 遍历,也可以使用性能比较高的 Stream 多线程遍历。

是非审之于己,毁誉听之于人,得失安之于数。

博主介绍:80 后程序员,写博客这件事“坚持”了 11 年,爱好:读书、慢跑、羽毛球。

我的公众号:Java面试真题解析

个人微信:GG_Stone,欢迎围观朋友圈,做个点赞只交。


往期推荐:

3ea52d2c4e995d20b3db5a4456c8e1f7.png

面试官:重写 equals 时为什么一定要重写 hashCode?


c7c35ac68d9fdaac0bbb8073a73ffed9.png

面试官:int和Integer有什么区别?为什么要有包装类?


ebb1486575bd7005873fbd7fed7668b9.png

面试官:final、finally、finalize 有什么区别?


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544425.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【逆强化学习-2】最大熵学习(Maximum Entropy Learning)

文章目录0.引言1.算法原理2.仿真0.引言 \qquad本文是逆强化学习系列的第2篇&#xff0c;其余博客传送门如下&#xff1a; 逆强化学习0-Introduction 逆强化学习1-学徒学习 \qquad最大熵学习是2008年出现的方法&#xff0c;原论文&#xff08;链接见【逆强化学习0】的博客&#…

面试官又整新活,居然问我for循环用i++和++i哪个效率高?

前几天&#xff0c;一个小伙伴告诉我&#xff0c;他在面试的时候被面试官问了这么一个问题&#xff1a;在for循环中&#xff0c;到底应该用 i 还是 i &#xff1f;听到这&#xff0c;我感觉这面试官确实有点不按套路出牌了&#xff0c;放着好好的八股文不问&#xff0c;净整些幺…

面试官:如何实现 List 集合去重?

作者 | 磊哥来源 | Java面试真题解析&#xff08;ID&#xff1a;aimianshi666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;本文已收录《Java常见面试题》系列&#xff0c;开源地址&#xff1a;https://gitee.com/mydb/interviewList 去重指的…

Windows重装Anaconda3失败解决方案【重装失败10来次首次成功的案例!】

文章目录0.环境1.原因2.解决方案0.环境 Win10 Anaconda3 2018版 python 3.7.1 注意&#xff01;此种情况只会在windows上发生&#xff0c;因为在linux上你只需要删除anaconda3整个文件夹&#xff0c;重新安装一定会成功&#xff01; 1.原因 Anaconda肯定是没有成功安装的&am…

python读取pcd点云/转numpy(python2+python3,非ROS环境)

0.引言 \qquadROS的PCL库支持python读取点云&#xff0c;ROS1关联的是python2&#xff08;2.7&#xff09;&#xff0c;ROS2关联的是python3&#xff08;>3.5&#xff09;&#xff0c;但这对于windows的用户和没装ROS的ubuntu用户似乎不够友好。下面就介绍两种不需要ros的方…

Java中List排序的3种方法!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;在某些特殊的场景下&#xff0c;我们需要在 Java 程序中对 List 集合进行排序操作。比如从第三方接口中获取所有用户的列表&…

Spring 事务失效的 8 种场景!

在日常工作中&#xff0c;如果对Spring的事务管理功能使用不当&#xff0c;则会造成Spring事务不生效的问题。而针对Spring事务不生效的问题&#xff0c;也是在跳槽面试中被问的比较频繁的一个问题。点击上方卡片关注我今天&#xff0c;我们就一起梳理下有哪些场景会导致Spring…

vscode无法识别constexpr

问题 vscode 无法识别constexpr&#xff08;常指针类型&#xff09; 方法 打开工程路径下的.vscode文件夹&#xff08;一般是自动隐藏的&#xff0c;CtrlH显示隐藏&#xff09;设置c_cpp_properties.json文件如下&#xff1a; {"configurations": [{"name…

三流Java搞技术,二流Java搞框架,一流Java…

如何反驳“99&#xff05; 的 Java 程序员都是 Spring 程序员”这句话&#xff1f;答案是不能。互联网发展至今&#xff0c;站在巨人肩膀上编程像一日三餐一样寻常。Spring Boot 的确凭一己之力拉低了 Java 开发的门槛&#xff0c;可普通开发与高开之间&#xff0c;真就因为一个…

【Ubuntu】vscode配置PCL库/vscode无法导入PCL库

问题 PCL库是ROS框架自带的点云处理库&#xff0c;可以通过find_package(PCL REQUIRED)在CMakeLists.txt中导入&#xff0c;但是vscode却无法识别&#xff0c;出现问题如下&#xff1a; 注意&#xff0c;本文解决方案仅限Ubuntu&#xff01; 解决方案 打开工程路径下的.vsc…

面试官:HashSet是如何保证元素不重复的?

作者 | 磊哥来源 | Java面试真题解析&#xff08;ID&#xff1a;aimianshi666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;本文已收录《Java常见面试题》系列&#xff0c;开源地址&#xff1a;https://gitee.com/mydb/interviewHashSet 实现…

【Ubuntu】Ubuntu 20.04无法识别网口/以太网/有线网卡

这里写自定义目录标题0.症状1.查看网卡类型2.下载网卡驱动3.安装网卡驱动0.症状 \qquad表现为插入以太网网口后右上角没有显示网络&#xff0c;即没有下图的音量左侧的标志 打开设置的【网络】选项没有以太网接入&#xff0c;然而以太网口信号灯仍然正常闪烁。这种情况基本可以…

小心Lombok用法中的坑

刚才写完了代码&#xff0c;自测的时候&#xff0c;出现了NPE问题。排查的时候发现是Lombok的坑&#xff0c;以前也遇到过&#xff0c;所以觉得有必要过来记录一下。我先描述一下现象&#xff0c;我的代码里面订单服务A 需要调用缓存服务B&#xff0c;服务B就是一个Bean&#x…

【VSCode】VSCode使用conda环境时找不到python包/找不到Module

这里写自定义目录标题0.问题描述1.原因2.解决方法0.问题描述 \qquad首先需要排除是否是VSCode未配置conda环境的问题&#xff0c;当然&#xff0c;相信VSCode的老粉都不会犯这个低级错误&#xff0c;请CtrlP&#xff0c;在搜索框>select interpreter检查一下python环境。 …

PS如何对JPG文件直接抠图

如何JPG文件直接抠图 先转为智能对象&#xff1a; 再栅格化图层 此进即可直接进行抠图&#xff01;

更快的Maven来了,我的天,速度提升了8倍!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;周末被 maven-mvnd 刷屏了&#xff0c;于是我也下载了一个 mvnd 体验了一把。虽然测试的数据都是基于我本地项目&#xff0c…

Java 中接口和抽象类竟然有 7 点不同?

作者 | 磊哥来源 | Java面试真题解析&#xff08;ID&#xff1a;aimianshi666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;本文已收录《Java常见面试题》系列&#xff1a;https://gitee.com/mydb/interviewJava 是一门面向对象的编程语言&am…

粉丝不在于多,在于够残

李善友&#xff1a;所有可能被互联网取代的组织一定会被取代 2015-07-30 格局视野 格局视野 格局视野 微信号 geju365 功能介绍 格局生涯学院官方自媒体。面向互联网人的在线商学院。推送互联网行业知识&#xff0c;培养互联网实操人才。聚焦新行业、新模式、新公司、新人物。…

保姆级教学:缓存穿透、缓存击穿和缓存雪崩!

前言对于从事后端开发的同学来说&#xff0c;缓存已经变成的项目中必不可少的技术之一。没错&#xff0c;缓存能给我们系统显著的提升性能。但如果你使用不好&#xff0c;或者缺乏相关经验&#xff0c;它也会带来很多意想不到的问题。今天我们一起聊聊如果在项目中引入了缓存&a…

Fast Global Registration (ECCV 2016) 论文解析

目录0.友情链接1. 论文核心思想1.1. 点云特征匹配1.2. 两个校验1.3. 鲁棒函数与BR对偶1.4.1. Black-Rangarjan Duality (BR对偶性&#xff09;1.4.2.Derivation of Φρ\Phi_\rhoΦρ​1.4.3.E(T,L)E(\bm{T},L)E(T,L)的优化求解方法4.写在后面0.友情链接 FGR基本介绍 CSDN博客…