写点什么

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

  • 2024-03-01
    福建
  • 本文字数:2970 字

    阅读完需:约 10 分钟

HashMap 的 7 种遍历方式


四大类遍历方式


其实在 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:I2:love3: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:I2:love3: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:I2:love3: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:I2:love3: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:I2:love3: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:I2:love3: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:I2:love3:Java
复制代码


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


总结


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


文章转载自:JavaBuild

原文链接:https://www.cnblogs.com/JavaBuild/p/18045685

体验地址:http://www.jnpfsoft.com/?from=001

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
面试官上来就让手撕HashMap的7种遍历方式,当场愣住,最后只写出了3种_Python_不在线第一只蜗牛_InfoQ写作社区