Java 中九种 Map 的遍历方式,你一般用的是哪种呢?

2024-01-05 19:50

本文主要是介绍Java 中九种 Map 的遍历方式,你一般用的是哪种呢?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Java 中九种 Map 的遍历方式,你一般用的是哪种呢?

日常工作中 Map 绝对是我们 Java 程序员高频使用的一种数据结构,那 Map 都有哪些遍历方式呢?这篇文章阿粉就带大家看一下,看看你经常使用的是哪一种。

通过 entrySet 来遍历

1、通过 formap.entrySet() 来遍历

第一种方式是采用 forMap.Entry 的形式来遍历,通过遍历 map.entrySet() 获取每个 entrykeyvalue,代码如下。这种方式一般也是阿粉使用的比较多的一种方式,没有什么花里胡哨的用法,就是很朴素的获取 map 的 keyvalue

public static void testMap1(Map<Integer, Integer> map) {long sum = 0;for (Map.Entry<Integer, Integer> entry : map.entrySet()) {sum += entry.getKey() + entry.getValue();}System.out.println(sum);}

看过 HashMap 源码的同学应该会发现,这个遍历方式在源码中也有使用,如下图所示,

图片

putMapEntries 方法在我们调用 putAll 方法的时候会用到。

图片

2、通过 forIteratormap.entrySet() 来遍历

我们第一个方法是直接通过 forentrySet() 来遍历的,这次我们使用 entrySet() 的迭代器来遍历,代码如下。

public static void testMap2(Map<Integer, Integer> map) {long sum = 0;for (Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator(); entries.hasNext(); ) {Map.Entry<Integer, Integer> entry = entries.next();sum += entry.getKey() + entry.getValue();}System.out.println(sum);}

3、通过 whileIteratormap.entrySet() 来遍历

上面的迭代器是使用 for 来遍历,那我们自然可以想到还可以用 while 来进行遍历,所以代码如下所示。

 public static void testMap3(Map<Integer, Integer> map) {Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();long sum = 0;while (it.hasNext()) {Map.Entry<Integer, Integer> entry = it.next();sum += entry.getKey() + entry.getValue();}System.out.println(sum);}

这种方法跟上面的方法类似,只不过循环从 for 换成了 while,日常我们在开发的时候,很多场景都可以将 forwhile 进行替换。2 和 3 都使用迭代器 Iterator,通过迭代器的 next(),方法来获取下一个对象,依次判断是否有 next

通过 keySet 来遍历

上面的这三种方式虽然代码的写法不同,但是都是通过遍历 map.entrySet() 来获取结果的,殊途同归。接下来我们看另外的一组。

4、通过 for 和 map.keySet() 来遍历

前面的遍历是通过 map.entrySet() 来遍历,这里我们通过 map.keySet() 来遍历,顾名思义前者是保存 entry 的集合,后者是保存 key 的集合,遍历的代码如下,因为是 key 的集合,所以如果想要获取 key 对应的 value 的话,还需要通过 map.get(key) 来获取。

public static void testMap4(Map<Integer, Integer> map) {long sum = 0;for (Integer key : map.keySet()) {sum += key + map.get(key);}System.out.println(sum);}

5、通过 forIteratormap.keySet() 来遍历

public static void testMap5(Map<Integer, Integer> map) {long sum = 0;for (Iterator<Integer> key = map.keySet().iterator(); key.hasNext(); ) {Integer k = key.next();sum += k + map.get(k);}System.out.println(sum);}

6、通过 whileIteratormap.keySet() 来遍历

public static void testMap6(Map<Integer, Integer> map) {Iterator<Integer> it = map.keySet().iterator();long sum = 0;while (it.hasNext()) {Integer key = it.next();sum += key + map.get(key);}System.out.println(sum);}

我们可以看到这种方式相对于 map.entrySet() 方式,多了一步 get 的操作,这种场景比较适合我们只需要 key 的场景,如果也需要使用 value 的场景不建议使用 map.keySet() 来进行遍历,因为会多一步 map.get() 的操作。

Java 8 的遍历方式

注意下面的几个遍历方法都是是 JDK 1.8 引入的,如果使用的 JDK 版本不是 1.8 以及之后的版本的话,是不支持的。

7、通过 map.forEach() 来遍历

JDK 中的 forEach 方法,使用率也挺高的。

public static void testMap7(Map<Integer, Integer> map) {final long[] sum = {0};map.forEach((key, value) -> {sum[0] += key + value;});System.out.println(sum[0]);}

该方法被定义在 java.util.Map#forEach 中,并且是通过 default 关键字来标识的,如下图所示。这里提个问题,为什么要使用 default 来标识呢?欢迎把你的答案写在评论区。

图片

8、Stream 遍历

public static void testMap8(Map<Integer, Integer> map) {long sum = map.entrySet().stream().mapToLong(e -> e.getKey() + e.getValue()).sum();System.out.println(sum);}

9、ParallelStream 遍历

 public static void testMap9(Map<Integer, Integer> map) {long sum = map.entrySet().parallelStream().mapToLong(e -> e.getKey() + e.getValue()).sum();System.out.println(sum);}

这两种遍历方式都是 JDK 8Stream 遍历方式,stream 是普通的遍历,parallelStream 是并行流遍历,在某些场景会提升性能,但是也不一定。

测试代码

上面的遍历方式有了,那么我们在日常开发中到底该使用哪一种呢?每一种的性能是怎么样的呢?为此阿粉这边通过下面的代码,我们来测试一下每种方式的执行时间。

public static void main(String[] args) {int outSize = 1;int mapSize = 200;Map<Integer, Integer> map = new HashMap<>(mapSize);for (int i = 0; i < mapSize; i++) {map.put(i, i);}System.out.println("---------------start------------------");long totalTime = 0;for (int size = outSize; size > 0; size--) {long startTime = System.currentTimeMillis();testMap1(map);totalTime += System.currentTimeMillis() - startTime;}System.out.println("testMap1 avg time is :" + (totalTime / outSize));// 省略其他方法,代码跟上面一致
}

为了避免一些干扰,这里通过外层的 for 来进行多次计算,然后求平均值,当我们的参数分别是 outSize = 1,mapSize = 200 的时候,测试的结果如下

图片

图片

当随着我们增大 mapSize 的时候,我们会发现,后面几个方法的性能是逐渐上升的。

图片

图片

总结

从上面的例子来看,当我们的集合数量很少的时候,基本上普通的遍历就可以搞定,不需要使用 JDK 8 的高级 API 来进行遍历,当我们的集合数量较大的时候,就可以考虑采用 JDK 8forEach 或者 Stream 来进行遍历,这样的话效率更高。在普通的遍历方法中 entrySet() 的方法要比使用 keySet() 的方法好。

个人推荐使用while、Tterator和entrySet()来遍历或者采用 JDK 8forEach 或者 Stream 来进行遍历。

这篇关于Java 中九种 Map 的遍历方式,你一般用的是哪种呢?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

一文详解如何在idea中快速搭建一个Spring Boot项目

《一文详解如何在idea中快速搭建一个SpringBoot项目》IntelliJIDEA作为Java开发者的‌首选IDE‌,深度集成SpringBoot支持,可一键生成项目骨架、智能配置依赖,这篇文... 目录前言1、创建项目名称2、勾选需要的依赖3、在setting中检查maven4、编写数据源5、开启热

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

Java对异常的认识与异常的处理小结

《Java对异常的认识与异常的处理小结》Java程序在运行时可能出现的错误或非正常情况称为异常,下面给大家介绍Java对异常的认识与异常的处理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参... 目录一、认识异常与异常类型。二、异常的处理三、总结 一、认识异常与异常类型。(1)简单定义-什么是

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志

《SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志》在SpringBoot项目中,使用logback-spring.xml配置屏蔽特定路径的日志有两种常用方式,文中的... 目录方案一:基础配置(直接关闭目标路径日志)方案二:结合 Spring Profile 按环境屏蔽关

Java使用HttpClient实现图片下载与本地保存功能

《Java使用HttpClient实现图片下载与本地保存功能》在当今数字化时代,网络资源的获取与处理已成为软件开发中的常见需求,其中,图片作为网络上最常见的资源之一,其下载与保存功能在许多应用场景中都... 目录引言一、Apache HttpClient简介二、技术栈与环境准备三、实现图片下载与保存功能1.

python判断文件是否存在常用的几种方式

《python判断文件是否存在常用的几种方式》在Python中我们在读写文件之前,首先要做的事情就是判断文件是否存在,否则很容易发生错误的情况,:本文主要介绍python判断文件是否存在常用的几种... 目录1. 使用 os.path.exists()2. 使用 os.path.isfile()3. 使用

SpringBoot排查和解决JSON解析错误(400 Bad Request)的方法

《SpringBoot排查和解决JSON解析错误(400BadRequest)的方法》在开发SpringBootRESTfulAPI时,客户端与服务端的数据交互通常使用JSON格式,然而,JSON... 目录问题背景1. 问题描述2. 错误分析解决方案1. 手动重新输入jsON2. 使用工具清理JSON3.

java中long的一些常见用法

《java中long的一些常见用法》在Java中,long是一种基本数据类型,用于表示长整型数值,接下来通过本文给大家介绍java中long的一些常见用法,感兴趣的朋友一起看看吧... 在Java中,long是一种基本数据类型,用于表示长整型数值。它的取值范围比int更大,从-922337203685477