日常工作中 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() 的方法好。

Java 中九种 Map 的遍历方式,你一般用的是哪种呢?的更多相关文章

  1. Java Map各遍历方式的性能比较

    1. 阐述 对于Java中Map的遍历方式,很多文章都推荐使用entrySet,认为其比keySet的效率高很多.理由是:entrySet方法一次拿到所有key和value的集合:而keySet拿到的 ...

  2. Java8 Map的遍历方式

    在这篇文章中,我将对Map的遍历方式做一个对比和总结,将分别从JAVA8之前和JAVA8做一个遍历方式的对比,亲测可行. public class LambdaMap { private Map< ...

  3. Java实现二叉树及相关遍历方式

    Java实现二叉树及相关遍历方式 在计算机科学中.二叉树是每一个节点最多有两个子树的树结构.通常子树被称作"左子树"(left subtree)和"右子树"(r ...

  4. Java8中Map的遍历方式总结

    在这篇文章中,我将对Map的遍历方式做一个对比和总结,将分别从JAVA8之前和JAVA8做一个遍历方式的对比,亲测可行. public class LambdaMap { private Map< ...

  5. python列表和字符串的三种逆序遍历方式

    python列表和字符串的三种逆序遍历方式 列表的逆序遍历 a = [1,3,6,8,9] print("通过下标逆序遍历1:") for i in a[::-1]: print( ...

  6. Java(8)中List的遍历方式总结

    本篇文章主要讲述了List这一集合类型在Java,包括Java8中的遍历方式,不包括其他的过滤,筛选等操作,这些操作将会在以后的文章中得到提现,由List可以类推到Set等类似集合的遍历方式. pub ...

  7. Map的遍历方式

    public class Mapper { public static void main(String[] args) {  Map<String, String> map = new ...

  8. Java基础之Map的遍历

    遍历Map集合,有四种方法:   public static void main(String[] args) { Map<String, String> map = new HashMa ...

  9. Java中的map的遍历方法

    public static void main(String[] args) { Map<String, String> map = new HashMap<String, Stri ...

  10. 一种map容器遍历的方法

    遍历算法是一种很常见而且非常重要的算法,我们用map容器的时候可能用的比较多的是查找,我今天才第一次要用到遍历.下面举个例子就知道了. map<string,string> mp; str ...

随机推荐

  1. Docker_删除所有容器

    删除所有容器 docker rm `docker ps -aq`

  2. aardio + .NET 快速开发独立 EXE 程序,可防 ILSpy 反编译

    简介 aardio 可以非常方便地调用 .NET( 不需要任何复杂的步骤 ). .NET 在 aardio 中很好用,系统自带 .NET 组件以及各种开源 .NET 组件在 aardio 用户中也很受 ...

  3. 使用【阿里云】服务器、【Xshell】搭建自己的【网站】—— { }

    重置实例密码 打开Xshell连接主机 Apache 服务 安装 yum install httpd* -y 操作 启动 systemctl start httpd.service 查看状态 syst ...

  4. JavaWeb核心篇(3)——JSP,MVC,三层架构

    JavaWeb核心篇(3)--JSP,MVC,三层架构 在本篇文章中我们会学习到JSP,MVC,三层架构 虽然JSP已经快被时代所淘汰,但是在一些老旧的工作场所还是有在使用,所以了解一下也不为过 至于 ...

  5. Elasticsearch:反向代理及负载均衡在 Elasticsearch 中的应用

    文章转载自:https://elasticstack.blog.csdn.net/article/details/108365746

  6. MongoDB分片集群-Sharded Cluster

    分片概念 分片(sharding)是一种跨多台机器分布数据的方法, MongoDB使用分片来支持具有非常大的数据集和高吞吐量操作的部署. 换句话说:分片(sharding)是指将数据拆分,将其分散存在 ...

  7. 【C++】从零开始的CS:GO逆向分析2——配置GLFW+IMGUI环境并创建透明窗口

    [C++]从零开始的CS:GO逆向分析2--配置GLFW+IMGUI环境并创建透明窗口   使用的环境:Visual Studio 2017,创建一个控制台程序作为工程文件 1.配置glfw 在git ...

  8. 微信小程序实现与登录

    一.小程序的实现原理 在小程序中,渲染层和逻辑层是分开的,双线程同时运行,渲染层和逻辑层这两个通信主体之间的通讯以及通讯主体与第三方服务器之间的通信,都是通过微信客户端进行转发.小程序启动运行两种情况 ...

  9. POJ3107 Godfather (树的重心)

    又是一道模板题...... 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using ...

  10. prometheus监控实战

    第一节.环境和软件版本 1.1.操作系统环境 主机ip 操作系统 部署软件 备注 192.168.10.10 Centos7.9 Grafana.Pushgateway.Blackbox Export ...