写在开头

今天有个小伙伴私信诉苦,说面试官上来就让他手撕HashMap的7种遍历方式,最终只写出3种常用的,怀疑面试官是在故意***难。这个问题大家怎么看?

反正我个人感觉这肯定不是***难,“手撕遍历方式” 算是一个比较简单的考验方式了,而且集合的遍历又是日常开发的必备!至于要一下写出7种,大概率是考验面试者平时学习的细心与自我总结能力,只要平时认真学习过,并且在日常代码开发中善于总结,善于归纳,完完全全写的出来呀。

HashMap的7种遍历方式

其实在这篇文章“耗时3天写完的HashMap万字解析,争取一篇文章讲透它,面试官看了都直点头!”中已经很详细的介绍了HashMap的相关知识点,以及常见面试题型,今天借着小伙伴的疑问,继续来唠一唠HashMap的遍历。

四大类遍历方式

其实在JDK1.8之前,遍历的方式远没有现在这样多,为了提高开发效率,JDK1.8开始引入了Stream流、Lambda 表达式等新特性,这让很多数据结构的遍历方式也丰富了起来。

目前,常用的遍历方式可以分为如下的4大类:

 1. 迭代器方式遍历;
2. ForEach方式遍历;
3. Lambda 表达式遍历;
4. Stream流方式遍历;

而这4个大类下其实又根据具体的实现形式,分为了很多小类,我们画一个思维导图直观的看一下。

1.使用迭代器EntrySet方式遍历

看过build哥之前文章的小伙伴应该对迭代器(Iterator)并不陌生,这里就不过多介绍了,感兴趣的朋友可以看这篇文章“面试官不按套路出牌,上来就让聊一聊Java中的迭代器(Iterator ),夺命连环问,怎么办?

话不多说,我们通过一个测试案例来感受一下map.entrySet().iterator()方式的遍历吧!

【代码示例1】

public class Test {
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "I");
map.put(2, "love");
map.put(3, "Java");
//迭代器(Iterator)EntrySet 的方式遍历
Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<Integer, String> entry = iterator.next();
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}

输出:

1:I
2:love
3:Java

这种方式,使用迭代器将map结合中的元素遍历出来,通过iterator.next()把对象的 key 和 value 值都放入到了 Entry 对象中。

2.使用迭代器KeySet方式遍历

这种方式与上一种几乎一样,都是借助迭代器进行的遍历,只是迭代器提供的另一种先获取key的形式,我们依旧写一个测试类来学习一下。

【代码示例2】

public class Test {
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "I");
map.put(2, "love");
map.put(3, "Java");
//迭代器(Iterator)KeySet 的方式遍历
Iterator<Integer> iterator = map.keySet().iterator();
while (iterator.hasNext()){
Integer key = iterator.next();
System.out.println(key+":"+map.get(key));
}
}
}

输出:

1:I
2:love
3:Java

虽然,两种方式输出的结果相同,但细心的朋友其实能够发现,通过keySet()遍历出来的只是键值对的key,我们要想完整的获取整个键值对数据,还需要通过HashMap的get方法,这样一来相当于又遍历了一遍,性能上自然逊色于entrySet()方式。

3.ForEach中EntrySet方式遍历

for循环我们应该都非常的熟悉,而for-each的写法,我们通常称之为增强for循环,代码相对简洁,是我们日常开发中比较常用的遍历方式,而在HashMap中我们同样可以结合for-each进行键值对遍历,看下面的代码。

【代码示例3】

public class Test {
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "I");
map.put(2, "love");
map.put(3, "Java");
//for-each结合EntrySet 的方式遍历
for (Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}

输出:

1:I
2:love
3:Java

怎么样?代码是不是简洁的多!这种方式同样是将遍历到的键值对存于map的entry对象中,然后通过get方法获取。

4.ForEach中KeySet方式遍历

话不多说,直接上代码!

【代码示例4】

public class Test {
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "I");
map.put(2, "love");
map.put(3, "Java");
//for-each结合KeySet 的方式遍历
for (Integer integer : map.keySet()) {
System.out.println(integer+":"+map.get(integer));
}
}
}

输出:

1:I
2:love
3:Java

代码同样很简洁,输出结果一致,仔细观察的朋友可能会发现,这里面虽然没有迭代器,但其实底层依旧是通过迭代器实现,我们看这样的一段代码:

【代码示例5】

for (String str : list) {
System.out.print(str + ",");
}

【反编译】

Iterator var3 = list.iterator();

while(var3.hasNext()) {
String str = (String)var3.next();
System.out.print(str + ",");
}

反编译后我们可以看得出,底层的实现就是迭代器,而这个for-each的写法不过是Java的一个语法糖罢了!

5.Lambda方式遍历

Lambda 表达式是推动 Java 8 发布的最重要新特性,它作为一种匿名函数,使得java8拥有了把函数作为参数传递进方法中的能力。

语法格式

(parameters) -> expression 或
(parameters) ->{ statements; }

【代码示例6】

public class Test {
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "I");
map.put(2, "love");
map.put(3, "Java");
//Lambda方式遍历
map.forEach((key,value) ->{
System.out.println(key+":"+value);
});
}
}

输出:

1:I
2:love
3:Java

6.Streams API 单线程场景下遍历方式

Java8的另外一个新特性就是stream流,可以通过流进行数据的检索、筛选、统计、排序等操作,由于它的方法参数都是函数式接口类型,因此,它通常和Lambda 配合使用。上代码!

流的使用有2种场景:

1,stream 串行流

2,parallelStream 并行流,可多线程执行

【代码示例7】

public class Test {
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "I");
map.put(2, "love");
map.put(3, "Java");
//Streams API 单线程时的遍历方式
map.entrySet().stream().forEach((entry)->{
System.out.println(entry.getKey()+":"+entry.getValue());
});
}
}

输出:

1:I
2:love
3:Java

7.Streams API 多线程场景下遍历方式

【代码示例8】

public class Test {
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "I");
map.put(2, "love");
map.put(3, "Java");
//Streams API 多线程场景下遍历方式
map.entrySet().parallelStream().forEach((entry)->{
System.out.println(entry.getKey()+":"+entry.getValue());
});
}
}

输出:

1:I
2:love
3:Java

看完了stream流的遍历方式后,我们可以看到,通过底层的实现,确实让我们的遍历方式更加丰富,并且提升了整个代码的流畅性与可读性。

总结

以上就是HashMap中常用的7种遍历方式了,在工作中还是经常用得到的,所以希望小伙伴们能够记住并熟练使用哈。

结尾彩蛋

如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!

如果您想与Build哥的关系更近一步,还可以关注俺滴公众号“JavaBuild888”,在这里除了看到《Java成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入!

面试官上来就让手撕HashMap的7种遍历方式,当场愣住,最后只写出了3种的更多相关文章

  1. HashMap的两种遍历方式

    HashMap的两种遍历方式 HashMap存储的是键值对:key-value . java将HashMap的键值对作为一个整体对象(java.util.Map.Entry)进行处理,这优化了Hash ...

  2. HashMap概述及其三种遍历方式

    一.HashMap概述: 1.HashMap是一个散列表,它存储的是键值对(key-value)映射: 2.HashMap继承AbstractMap,实现了Map,Cloneable,Serializ ...

  3. HashMap 中7种遍历方式的性能分析

    随着 JDK 1.8 Streams API 的发布,使得 HashMap 拥有了更多的遍历的方式,但应该选择那种遍历方式?反而成了一个问题. 本文先从 HashMap 的遍历方法讲起,然后再从性能. ...

  4. HashMap 的 7 种遍历方式与性能分析

    前言 随着 JDK 1.8 Streams API 的发布,使得 HashMap 拥有了更多的遍历的方式,但应该选择那种遍历方式?反而成了一个问题. 本文先从 HashMap 的遍历方法讲起,然后再从 ...

  5. HashMap两种遍历方式的深入研究

    转自:http://swiftlet.net/archives/1259 HashMap的遍历有两种方式,如下所示:第一种利用entrySet的方式:   1 2 3 4 5 6 7 Map map ...

  6. Java中的HashMap的2种遍历方式比较

    首先我们准备数据,准备一个map Map<String, String> map = new HashMap<String, String>(); for (int i = 0 ...

  7. Java HashMap 四种遍历方式

    HashMap遍历方式包含以下4种: 1.遍历KeySet,再通过Key来getValue. 2.使用entrySet的迭代器. 3.foreach entrySet的方式. 3.foreache v ...

  8. 谨慎使用keySet:对于HashMap的2种遍历方式比较

    HashMap存储的是键值对,所以一般情况下其遍历同List及Set应该有所不同. 但java巧妙的将HashMap的键值对作为一个整体对象(java.util.Map.Entry)进行处理,这优化了 ...

  9. 手撕HashMap

    前言: 平时工作的时候,用的最多的就是ArrayList和HashMap了,今天看了遍HashMap的源码,决定自己手写一遍HashMap. 一.创建MyHashMap接口       我们首先创建一 ...

  10. Java HashMap两种遍历方式

    第一种: Map map = new HashMap(); Iterator iter = map.entrySet().iterator(); while (iter.hasNext()) { Ma ...

随机推荐

  1. firewall-cmd 命令简单总结

    最近进行相关网络设置, 发现需要总结一下不然总是会忘记. # 1. 开放IP地址访问 firewall-cmd --zone=trusted --add-source=yourip --permane ...

  2. Orika JavaBean映射工具使用

    作者:京东零售 张宾 1.Orika是什么? Orika是一个简单.快速的JavaBean拷贝框架,它能够递归地将数据从一个JavaBean复制到另一个JavaBean,这在多层应用开发中是非常有用的 ...

  3. 如何去掉 node.js 获取MySQL数据产生的RowDataPacket

    如何去掉 node.js 获取MySQL数据产生的RowDataPacket 利用JSON.stringify()把对象转为对象字符串,可去掉RowDataPacket. router.post('/ ...

  4. ClickHouse(14)ClickHouse合并树MergeTree家族表引擎之VersionedCollapsingMergeTree详细解析

    目录 建表语法 使用场景 合并算法 使用例子. 资料分享 参考文章 VersionedCollapsingMergeTree引擎继承自MergeTree并将折叠行的逻辑添加到合并数据部分的算法中.Ve ...

  5. 英伟达系列显卡大解析B100、H200、L40S、A100、A800、H100、H800、V100如何选择,含架构技术和性能对比带你解决疑惑

    英伟达系列显卡大解析B100.H200.L40S.A100.A800.H100.H800.V100如何选择,含架构技术和性能对比带你解决疑惑 近期,AIGC领域呈现出一片繁荣景象,其背后离不开强大算力 ...

  6. 强化学习从基础到进阶-案例与实践[5.1]:Policy Gradient策略梯度-Cart pole游戏展示

    强化学习从基础到进阶-案例与实践[5.1]:Policy Gradient策略梯度-Cart pole游戏展示 强化学习(Reinforcement learning,简称RL)是机器学习中的一个领域 ...

  7. 21.10 Python 使用CRC32校验文件

    CRC文件校验是一种用于验证文件完整性的方法,通过计算文件的CRC值并与预先计算的CRC校验值进行比较,来判断文件是否发生变化,此类功能可以用于验证一个目录中是否有文件发生变化,如果发生变化则我们可以 ...

  8. 解决线程不安全的方式(Java)

    一.同步代码块 package com.synchronized1; // 买票示例 // 使用同步代码块解决线程安全问题 public class TicketRunnableImp impleme ...

  9. nginx+uwsgi环境部署

    WSGI django自带的wsgiref 在调试模式下使用的wsgi的文件,网关接口,协议 uwsgi:协议 uWSGI:具体实现方式 安装 ``` pip3 install uwsgi -i ht ...

  10. 从CPU100%高危故障到稳定在10%:一个月的优化之旅,成功上线!

    引言 经过三个月的开发,项目通过了所有测试并上线,然而,我们发现项目的首页几乎无法打开,后台一直发生超时错误,导致CPU过度负荷.在这次项目开发过程中,我制定了一份详细的技术优化方案.考虑到客户无法提 ...