Java HashMap遍历实践,看看不同方式的性能如何

简介: 版权声明:欢迎转载,请注明沉默王二原创。 https://blog.csdn.net/qing_gee/article/details/50801937 在原始记忆中,Java HashMap遍历,无非是for each或者iterator,但至于在遍历时性能如何,优缺点如何,泛泛而不得知。
版权声明:欢迎转载,请注明沉默王二原创。 https://blog.csdn.net/qing_gee/article/details/50801937

在原始记忆中,Java HashMap遍历,无非是for each或者iterator,但至于在遍历时性能如何,优缺点如何,泛泛而不得知。对于这样的基础问题,对于王二(Java编程6年,幸好我的方向不是编程)我来说,似乎羞于提及,但事实证明,我还必须“积硅步”。

①方法一、iterator迭代keys并搜索values

该种方法是我使用最频繁的,没有之一,详见如下代码:

Map<Integer, Integer> map = new HashMap<Integer, Integer>();

addMap(map);

long t1 = System.currentTimeMillis();
Iterator<Integer> keys = map.keySet().iterator();

while (keys.hasNext()) {
    Integer key = keys.next();
    Integer value = map.get(key);

    keys.remove();
}

long t2 = System.currentTimeMillis();
System.out.println("map.keySet().iterator()耗时:" + (t2 - t1));

以前的我看来,该种方法使用起来相当简洁,通过iterator遍历出来keys,然后通过key从map中获取对应的value,似乎也非常接地气。但是,弊端就在于

它更慢更低效,通过key得到value值更耗时(这个方法在所有实现map接口的map中比方法#1慢20%-200%)。如果你安装了FindBugs,它将检测并警告你这是一个低效的迭代。这个方法应该避免

看到这条信息,我是觉得有点唐突,怎么原来最喜欢的一种map遍历方式竟然如此low,简直让人失望。后面我会对花费的性能时间做一个统计,稍候关注。

②方法二、Iterator迭代Entry

这种方法我以前几乎不用,但方法二却有其关键的优点:

  1. 可以通过iterator对map的元素进行删除。方法一同样。
  2. 性能优良。
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
addMap(map);

long t3 = System.currentTimeMillis();
Iterator<Entry<Integer, Integer>> entrys = map.entrySet().iterator();

while (entrys.hasNext()) {
    Entry<Integer, Integer> entry = entrys.next();
    Integer key = entry.getKey();
    Integer value = entry.getValue();

    entrys.remove();
}

long t4 = System.currentTimeMillis();
System.out.println(" map.entrySet().iterator()耗时:" + (t4 - t3));

通过“map.entrySet().iterator()”获得map的entry对象,然后通过getKey,getValue进行key和value值得获取,非常的直白和实用。

③方法三:For-Each迭代keys和values

for each一个局限是不同remove map中的元素,但遍历map还是非常好的。

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
addMap(map);

long t5 = System.currentTimeMillis();
for (Integer key : map.keySet()) {
}

for (Integer value : map.values()) {
}
long t6 = System.currentTimeMillis();
System.out.println("for each map.keySet()、map.values()耗时:" + (t6 - t5));

不过这里,王二有话要说,按照stackoverflow上所说,该种方法要比接下来说的第四种方法“For-Each迭代entries”性能更好(大约快10%),但在我的实践中并非如此,这种方法反而比第四种“For-Each迭代entries”慢得多。

④方法四:For-Each迭代entries

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
addMap(map);

long t7 = System.currentTimeMillis();
for (Entry<Integer, Integer> entry : map.entrySet()) {
    Integer key = entry.getKey();
    Integer value = entry.getValue();
}
long t8 = System.currentTimeMillis();
System.out.println("for each map.entrySet()耗时:" + (t8 - t7));

这种方法就不多做介绍了。

⑤性能时间表

次序 iterator迭代keys并搜索values Iterator迭代Entry For-Each迭代keys和values For-Each迭代entries
1 耗时:37 耗时:32 耗时:39 耗时:13
2 耗时:29 耗时:18 耗时:32 耗时:15
3 耗时:50 耗时:57 耗时:39 耗时:21
4 耗时:47 耗时:31 耗时:39 耗时:14

可以总结如下:

  1. 迭代keys并搜索values 非常低效,排名几乎在倒数第一或第二
  2. For-Each迭代entries 性能最佳,但无法remove
  3. For-Each迭代keys和values并没有比For-Each迭代entries 性能(大约快10%),stackoverflow上的数据也不能全部苟同
  4. Iterator迭代Entry 的方案显然最适合使用,性能优良,且可以remove

参考文章


感谢您阅读【沉默王二的博客】,如果王二的博客给您带来一丝帮助或感动,我(也就是王二)将不甚荣幸。
如果您碰巧喜欢,可以留言或者私信我,这将是我鼓捣更多优秀文章的最强动力。

相关文章
|
20天前
|
Java 调度
Java并发编程:深入理解线程池的原理与实践
【4月更文挑战第6天】本文将深入探讨Java并发编程中的重要概念——线程池。我们将从线程池的基本原理入手,逐步解析其工作过程,以及如何在实际开发中合理使用线程池以提高程序性能。同时,我们还将关注线程池的一些高级特性,如自定义线程工厂、拒绝策略等,以帮助读者更好地掌握线程池的使用技巧。
|
22天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第3天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin的兴起,其在Android开发中的地位逐渐上升,但关于其与Java在性能方面的对比,尚无明确共识。本文通过深入分析并结合实际测试数据,探讨了Kotlin与Java在Android平台上的性能表现,揭示了在不同场景下两者的差异及其对应用性能的潜在影响,为开发者在选择编程语言时提供参考依据。
|
21天前
|
Java 程序员 调度
Java中的多线程编程:基础知识与实践
【4月更文挑战第5天】 在现代软件开发中,多线程编程是一个不可或缺的技术要素。它允许程序员编写能够并行处理多个任务的程序,从而充分利用多核处理器的计算能力,提高应用程序的性能。Java作为一种广泛使用的编程语言,提供了丰富的多线程编程支持。本文将介绍Java多线程编程的基础知识,并通过实例演示如何创建和管理线程,以及如何解决多线程环境中的常见问题。
|
16天前
|
Java 数据挖掘
java实践
【4月更文挑战第9天】java实践
12 1
|
21小时前
|
数据采集 存储 Java
高德地图爬虫实践:Java多线程并发处理策略
高德地图爬虫实践:Java多线程并发处理策略
|
2天前
|
IDE Java 开发工具
Java从入门到精通:1.3.1实践编程巩固基础知识
Java从入门到精通:1.3.1实践编程巩固基础知识
|
8天前
|
安全 Java 程序员
Java中的多线程并发编程实践
【4月更文挑战第18天】在现代软件开发中,为了提高程序性能和响应速度,经常需要利用多线程技术来实现并发执行。本文将深入探讨Java语言中的多线程机制,包括线程的创建、启动、同步以及线程池的使用等关键技术点。我们将通过具体代码实例,分析多线程编程的优势与挑战,并提出一系列优化策略来确保多线程环境下的程序稳定性和性能。
|
9天前
|
负载均衡 Java 开发者
细解微服务架构实践:如何使用Spring Cloud进行Java微服务治理
【4月更文挑战第17天】Spring Cloud是Java微服务治理的首选框架,整合了Eureka(服务发现)、Ribbon(客户端负载均衡)、Hystrix(熔断器)、Zuul(API网关)和Config Server(配置中心)。通过Eureka实现服务注册与发现,Ribbon提供负载均衡,Hystrix实现熔断保护,Zuul作为API网关,Config Server集中管理配置。理解并运用Spring Cloud进行微服务治理是现代Java开发者的关键技能。
|
9天前
|
Java API 数据库
深研Java异步编程:CompletableFuture与反应式编程范式的融合实践
【4月更文挑战第17天】本文探讨了Java中的CompletableFuture和反应式编程在提升异步编程体验上的作用。CompletableFuture作为Java 8引入的Future扩展,提供了一套流畅的链式API,简化异步操作,如示例所示的非阻塞数据库查询。反应式编程则关注数据流和变化传播,通过Reactor等框架实现高度响应的异步处理。两者结合,如将CompletableFuture转换为Mono或Flux,可以兼顾灵活性和资源管理,适应现代高并发环境的需求。开发者可按需选择和整合这两种技术,优化系统性能和响应能力。
|
9天前
|
网络协议 Java API
深度剖析:Java网络编程中的TCP/IP与HTTP协议实践
【4月更文挑战第17天】Java网络编程重在TCP/IP和HTTP协议的应用。TCP提供可靠数据传输,通过Socket和ServerSocket实现;HTTP用于Web服务,常借助HttpURLConnection或Apache HttpClient。两者结合,构成网络服务基础。Java有多种高级API和框架(如Netty、Spring Boot)简化开发,助力高效、高并发的网络通信。