文章目录

  • 一、写在前面
  • 二、正式开始探究之旅
    • 1. Map集合一共有多少种遍历方式呢?
    • 2.那这几种遍历方式的具体用法是啥样的呢?
      • 2.1 keySet()方式遍历-------for循环
      • 2.2 keySet()方式遍历-------Iterator迭代
      • 2.3 entrySet()方式遍历-------for循环
      • 2.4 entrySet()方式遍历-------Iterator迭代
      • 2.5 values()方式遍历-------for循环
      • 2.6 values()方式遍历-------Iterator迭代
      • 2.7 JDK8-------Lambda表达式forEach遍历
    • 3. 那这几种遍历方式的性能如何呢?哪一种更推荐使用呢?
      • 3.1首先,我们来准备一下测试数据
      • 3.2打印各种遍历方式遍历测试数据的执行时间
      • 3.3测试结果
  • 三、写在最后
  • 四、附录--全部测试源码

一、写在前面

 好久不见。一转眼,新的一年已经走过了两个月,距离上次更新博客也相隔好几个月,原本打算月更的我,也因为工作和懒散,走上了拖更之路。不过,我小宗又回来了!

今天,让我们来探究一个老生常谈的问题:Map集合的遍历。这同时也是许多Java初学者必须要掌握的基础知识,网上也有很多大神很多博客对此进行讲解。此博文从知识层面上借鉴之,并记录于2021年2月3日16:13:15。


二、正式开始探究之旅

1. Map集合一共有多少种遍历方式呢?

Map集合主要有三种遍历方式:keySet()、entrySet()、values()。但是,如果从API层面上进行细分的话有7种。这三种各自都有两种形式,for循环和Iterator迭代。还有最后一种,如果你是JDK8以上版本,还可以使用Lambda表达式forEach遍历

2.那这几种遍历方式的具体用法是啥样的呢?

下面,我使用IDEA新建一个项目,进行demo编写演示。具体的IDEA操作不属于本文的研究重点,略去不表。直接在test下面写测试案例。

2.1 keySet()方式遍历-------for循环

     //2.1 keySet()方式遍历-------for循环long keySetForStartTime = System.nanoTime();for (String key : map.keySet()) {map.get(key);}long keySetForEndTime = System.nanoTime();

2.2 keySet()方式遍历-------Iterator迭代

     //2.2 keySet()方式遍历-------Iterator迭代long keySetIteratorStartTime = System.nanoTime();Iterator<String> iterator1 = map.keySet().iterator();while (iterator1.hasNext()) {String key = iterator1.next();map.get(key);}long keySetIteratorEndTime = System.nanoTime();

2.3 entrySet()方式遍历-------for循环

     long entrySetForStartTime = System.nanoTime();for (Map.Entry<String, String> entry : map.entrySet()) {entry.getKey();entry.getValue();}long entrySetForEndTime = System.nanoTime();

2.4 entrySet()方式遍历-------Iterator迭代

     long entrySetIteratorStartTime = System.nanoTime();Iterator<Map.Entry<String, String>> iterator2 = map.entrySet().iterator();while (iterator2.hasNext()) {Map.Entry<String, String> entry = iterator2.next();entry.getKey();entry.getValue();}long entrySetIteratorEndTime = System.nanoTime();

2.5 values()方式遍历-------for循环

     long valuesForStartTime = System.nanoTime();Collection<String> values = map.values();for (String value : values) {//.....}long valuesForEndTime = System.nanoTime();

2.6 values()方式遍历-------Iterator迭代

     //2.6 values()方式遍历-------Iterator迭代long valuesIteratorStartTime = System.nanoTime();Iterator<String> iterator3 = map.values().iterator();while (iterator3.hasNext()) {String value = iterator3.next();}long valuesIteratorEndTime = System.nanoTime();

2.7 JDK8-------Lambda表达式forEach遍历

     //2.7 JDK8-------Lambda表达式forEach遍历long forEachStartTime = System.nanoTime();map.forEach((key, value) -> {//......});long forEachEndTime = System.nanoTime();

JDK8Lambda表达式的forEach方法,其实就是一种语法糖,让你的代码更加简洁,使用更加方便,深入源码,我们可以很轻易的发现,它其实就是对entrySet遍历方式的一种包装而已。不信你看下面我贴的forEach源码。

forEach源码。本方法since1.8版本

     * @param action The action to be performed for each entry* @throws NullPointerException if the specified action is null* @throws ConcurrentModificationException if an entry is found to be* removed during iteration* @since 1.8*/default void forEach(BiConsumer<? super K, ? super V> action) {Objects.requireNonNull(action);for (Map.Entry<K, V> entry : entrySet()) {K k;V v;try {k = entry.getKey();v = entry.getValue();} catch(IllegalStateException ise) {// this usually means the entry is no longer in the map.throw new ConcurrentModificationException(ise);}action.accept(k, v);}}

3. 那这几种遍历方式的性能如何呢?哪一种更推荐使用呢?

3.1首先,我们来准备一下测试数据

我们实例化一个HashMap对象,往Map中添加一百万条数据,以此作为测试数据。

     //准备Map,装入测试数据Map<String, String> map = new HashMap<>();//往map里插入一百万数据,作为测试数据,别怕,家里就这条件for (int i = 0; i < 1000000; i++) {map.put(String.valueOf(i), "我是第" + i + "名");}

3.2打印各种遍历方式遍历测试数据的执行时间

由于在上一部分的API使用的代码中,我们已经穿插进去计算执行时间的代码,下面我们可以直接打印时间差,作为每种遍历方式的执行时间,虽然不是很严格,但是也能从结果中看得比较明显。

     System.out.println("keySet()方式遍历-------for循环用时:" + (keySetForEndTime - keySetForStartTime) / 1000000 + "毫秒");System.out.println("keySet()方式遍历-------Iterator迭代用时:" + (keySetIteratorEndTime - keySetIteratorStartTime) / 1000000 + "毫秒");System.out.println("entrySet()方式遍历-------for循环用时:" + (entrySetForEndTime - entrySetForStartTime) / 1000000 + "毫秒");System.out.println("entrySet()方式遍历-------Iterator迭代用时:" + (entrySetIteratorEndTime - entrySetIteratorStartTime) / 1000000 + "毫秒");System.out.println("values()方式遍历-------for循环用时:" + (valuesForEndTime - valuesForStartTime) / 1000000 + "毫秒");System.out.println("values()方式遍历-------Iterator迭代用时:" + (valuesIteratorEndTime - valuesIteratorStartTime) / 1000000 + "毫秒");System.out.println("JDK8-------Lambda表达式forEach遍历用时:" + (forEachEndTime - forEachStartTime) / 1000000 + "毫秒");

3.3测试结果


结果分析:
直接抛出结论,entrySet()方式比keySet()方式效率更高,在忽略其他条件下,对于同一种遍历方式而言,Iterator迭代比for循环效率高。

当然,上述的结论只是说出了一半。其实是分两种情况的。在元素数量大的情况下,entrySet()性能确实是优于keySet()的,越大越明显。同样的,在小数据量的情况下,keySet()效率更高一点。

为啥大数据量时,entrySet()效率高呢?

其实,keySet()遍历,其实是相当于遍历了两次,第一次是转换为Iterator对象,第二次才是根据key从Map中取出对应的value值。而entrySet()转成Entry对象,只遍历一次。
当然,还有其他的一些原因,比如,map.get(key),这一操作注定了是计算密集型操作,很耗费CPU,在此不再过多说明。

values()方式的说明

values(),顾名思义,它得到的是Map中value的集合,因此,想要获取value对应的key值比较困难,因此使用上还是看需求。

在日常的开发工作中推荐使用哪一种遍历方式呢?

直接说结论:推荐使用entrySet()遍历方式,这依然是不二之选。并不是很建议使用keySet方式。如果项目是JDK8以上的版本,直接使用forEach吧,底层原理一样,语法更好更简洁,何乐而不为呢?


三、写在最后

虽然本文比较基础,但对于初学者而言,依然是比较重要的一节课,毕竟这种数据结构的使用在日常的项目开发中,不可或缺。算是写了一篇水文,也算是延续继续更下去的习惯吧。

后续有时间可能会更一篇Java的数据结构,LIst、Map、Set等的底层原理以及JDK7、8版本底层的升级。

也有可能会研究一下Redis的使用。

谁又说的准呢?

毕竟下一次更文,还不知道呢。哈哈

我是小宗,Java学习,我和你一样,一直在路上。加油!

四、附录–全部测试源码

@Testvoid testMap() {//准备Map,装入测试数据Map<String, String> map = new HashMap<>();//往map里插入一百万数据,作为测试数据,别怕,家里就这条件for (int i = 0; i < 1000000; i++) {map.put(String.valueOf(i), "我是第" + i + "名");}//2.1 keySet()方式遍历-------for循环long keySetForStartTime = System.nanoTime();for (String key : map.keySet()) {map.get(key);}long keySetForEndTime = System.nanoTime();//2.2 keySet()方式遍历-------Iterator迭代long keySetIteratorStartTime = System.nanoTime();Iterator<String> iterator1 = map.keySet().iterator();while (iterator1.hasNext()) {String key = iterator1.next();map.get(key);}long keySetIteratorEndTime = System.nanoTime();//2.3 entrySet()方式遍历-------for循环long entrySetForStartTime = System.nanoTime();for (Map.Entry<String, String> entry : map.entrySet()) {entry.getKey();entry.getValue();}long entrySetForEndTime = System.nanoTime();//2.4 entrySet()方式遍历-------Iterator迭代long entrySetIteratorStartTime = System.nanoTime();Iterator<Map.Entry<String, String>> iterator2 = map.entrySet().iterator();while (iterator2.hasNext()) {Map.Entry<String, String> entry = iterator2.next();entry.getKey();entry.getValue();}long entrySetIteratorEndTime = System.nanoTime();//2.5 values()方式遍历-------for循环long valuesForStartTime = System.nanoTime();Collection<String> values = map.values();for (String value : values) {//.....}long valuesForEndTime = System.nanoTime();//2.6 values()方式遍历-------Iterator迭代long valuesIteratorStartTime = System.nanoTime();Iterator<String> iterator3 = map.values().iterator();while (iterator3.hasNext()) {String value = iterator3.next();}long valuesIteratorEndTime = System.nanoTime();//2.7 JDK8-------Lambda表达式forEach遍历long forEachStartTime = System.nanoTime();map.forEach((key, value) -> {//......});long forEachEndTime = System.nanoTime();System.out.println("keySet()方式遍历-------for循环用时:" + (keySetForEndTime - keySetForStartTime) / 1000000 + "毫秒");System.out.println("keySet()方式遍历-------Iterator迭代用时:" + (keySetIteratorEndTime - keySetIteratorStartTime) / 1000000 + "毫秒");System.out.println("entrySet()方式遍历-------for循环用时:" + (entrySetForEndTime - entrySetForStartTime) / 1000000 + "毫秒");System.out.println("entrySet()方式遍历-------Iterator迭代用时:" + (entrySetIteratorEndTime - entrySetIteratorStartTime) / 1000000 + "毫秒");System.out.println("values()方式遍历-------for循环用时:" + (valuesForEndTime - valuesForStartTime) / 1000000 + "毫秒");System.out.println("values()方式遍历-------Iterator迭代用时:" + (valuesIteratorEndTime - valuesIteratorStartTime) / 1000000 + "毫秒");System.out.println("JDK8-------Lambda表达式forEach遍历用时:" + (forEachEndTime - forEachStartTime) / 1000000 + "毫秒");}

Java集合篇:Map集合的几种遍历方式及性能测试相关推荐

  1. Java实现二叉树的创建与四种遍历方式(前,中,后,层)

    文章目录 1.二叉树节点的创建 2.二叉树的先序遍历 3.二叉树的中序遍历 4.二叉树的后序遍历 5.二叉树的层序遍历

  2. Map集合的几种遍历方式

    Map<String ,String> map=new HashMap<String,String>(); map.put("1","value1 ...

  3. java map遍历_Java中Map集合的两种遍历方式

    Java中的map遍历有多种方法,从最早的Iterator,到java5支持的foreach,再到java8 Lambda,让我们一起来看下Java中Map集合的两种遍历方式! 关于遍历Map集合的几 ...

  4. java中两种遍历集合的方式_Java中Map集合的两种遍历方式

    Java中的map遍历有多种方法,从最早的Iterator,到java5支持的foreach,再到java8 Lambda,让我们一起来看下Java中Map集合的两种遍历方式! 关于遍历Map集合的几 ...

  5. java 中map_Java Map集合详解

    Map 是一种键-值对(key-value)集合,Map 集合中的每一个元素都包含一个键对象和一个值对象.其中,键对象不允许重复,而值对象可以重复,并且值对象还可以是 Map 类型的,就像数组中的元素 ...

  6. Java中List集合的三种遍历方式(全网最详)

    Map集合:链接: Map集合的五种遍历方式及Treemap方法 Set集合:链接: Java中遍历Set集合的三种方法 TreeSet集合:链接: Java深入了解TreeSet,和迭代器遍历方法 ...

  7. Java进阶(七)Set系列集合、Map集合体系

    七.Set系列集合.Map集合体系 需要学会什么? Set系列集合的特点:Set系列集合的特点和底层原理. 集合工具类Collections:快速的对集合进行元素的添加.排序等操作. 综合案例:把Co ...

  8. JAVA中的Map集合

    JAVA中的Map集合 1.Map简介 java.util.map接口 1.Map称为查找表,该数据结构的样子是一个"多行两列"的表格,左列为key,右列为value,Map总是根 ...

  9. java进阶开发-----Set集合、Map集合(接java集合)

    (一).Set系列集合 Set系列集合特点 无序:存取顺序不一致 不重复:可以去除重复 无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素. Set集合实现类特点 Ha ...

最新文章

  1. Tensorflow 全网最全学习资料汇总之框架平台的综合对比【3】
  2. noip2016普及组 魔法阵vijos2012
  3. windows常用命令(高级语句篇)
  4. Windows Internals 笔记——错误处理
  5. 安装node-sass运行报错 Module build failed: TypeError: this.getResolve is not a function at Object.loader
  6. stoi() 函数----将一个string类型转换为int型
  7. 【深圳云栖大会】阿里云弹性计算ESSD云盘产品全面解析
  8. java 导出bcp文件格式_使用BCP导出导入数据
  9. 互联网晚报 | 3月22日 星期二 |​ ​工作人员标注mu5735残骸并展开调查;万门大学疑似解散VIP群跑路...
  10. 习题:Dual Matrices(思路题/分治)
  11. php txt 下载文件,PHP下载单个TXT文件
  12. Android Studio报错: Alternatively, to transfer the license agreements from one workstation to another
  13. Redis如何实现故障自动恢复?
  14. 与体育行业有关的e–r图_国家体育产业统计分类
  15. 和python哪个容易胖_哪些吃了最容易长胖呢?
  16. 苹果系统和安卓系统的区别_又一款影视APP,这次支持苹果安卓双系统!
  17. android activity 旋转,Android 设定横屏,禁止屏幕旋转,Activity重置
  18. ovftool导出虚拟机报错处理过程!
  19. Excel2——在同一个图中如何绘制多条曲线并标注图例
  20. C#中的DoEvents()

热门文章

  1. Java 与排序算法(2):选择排序
  2. 计算机动画_3dsmax的使用(二)
  3. 【论文导读】 - 关于联邦图神经网络的3篇文章
  4. 酒店OTT小区IPTV完整解决方案
  5. 人民币数字转人民币大写的函数
  6. 帧间预测(三)symmetric MVD mode
  7. 讲给后台程序员看的前端系列教程(52)——Bootstrap轮播图
  8. matlab十进制转二进制补码函数
  9. MQTT搭建(Windows和Linux)版
  10. GPT_MBR与GPT分区扫盲,希捷2T、3T硬盘测评(多图杀猫)。申精!