转自:http://www.webtag123.com/java/2949.html
1. 阐述
对于Java中Map的遍历方式,很多文章都推荐使用entrySet,认为其比keySet的效率高很多。理由是:entrySet方法一次拿到所有key和value的集合;而keySet拿到的只是key的集合,针对每个key,都要去Map中额外查找一次value,从而降低了总体效率。那么实际情况如何呢?
为了解遍历性能的真实差距,包括在遍历key+value、遍历key、遍历value等不同场景下的差异,我试着进行了一些对比测试。
2. 对比测试
一开始只进行了简单的测试,但结果却表明keySet的性能更好,这一点让我很是费解,不都说entrySet明显好于keySet吗?为了进一步地进行验证,于是采用了不同的测试数据进行更详细的对比测试。
2.1 测试数据
2.1.1 HashMap测试数据
HashMap-1,大小为100万,key和value均为String,key的值为1、2、3……1000000:
Map<String, String> map = new HashMap<String, String>(); String key, value; for (i = 1; i <= num; i++) { key = "" + i; value = "value"; map.put(key, value); }
HashMap-2,大小为100万,key和value均为String,key的值为50、100、150、200、……、50000000:
Map<String, String> map = new HashMap<String, String>(); String key, value; for (i = 1; i <= num; i++) { key = "" + (i * 50); value = "value"; map.put(key, value); }
2.1.2 TreeMap测试数据
TreeMap-1,大小为100万,key和value均为String,key的值为1、2、3……1000000:
Map<String, String> map = new TreeMap<String, String>(); String key, value; for (i = 1; i <= num; i++) { key = "" + i; value = "value"; map.put(key, value); }
TreeMap-2,大小为100万,key和value均为String,key的值为50、100、150、200、……、50000000,更离散:
Map<String, String> map = new TreeMap<String, String>(); String key, value; for (i = 1; i <= num; i++) { key = "" + (i * 50); value = "value"; map.put(key, value); }
2.2 测试场景
分别使用keySet、entrySet和values的多种写法测试三种场景:遍历key+value、遍历key、遍历value的场景。
2.2.1 遍历key+value
keySet遍历key+value(写法1):
Iterator<String> iter = map.keySet().iterator(); while (iter.hasNext()) { key = iter.next(); value = map.get(key); }
keySet遍历key+value(写法2):
for (String key : map.keySet()) { value = map.get(key); }
entrySet遍历key+value(写法1):
Iterator<Entry<String, String>> iter = map.entrySet().iterator(); Entry<String, String> entry; while (iter.hasNext()) { entry = iter.next(); key = entry.getKey(); value = entry.getValue(); }
entrySet遍历key+value(写法2):
for (Entry<String, String> entry: map.entrySet()) { key = entry.getKey(); value = entry.getValue(); }
2.2.2 遍历key
keySet遍历key(写法1):
Iterator<String> iter = map.keySet().iterator(); while (iter.hasNext()) { key = iter.next(); }
keySet遍历key(写法2):
for (String key : map.keySet()) { }
entrySet遍历key(写法1):
Iterator<Entry<String, String>> iter = map.entrySet().iterator(); while (iter.hasNext()) { key = iter.next().getKey(); }
entrySet遍历key(写法2):
for (Entry<String, String> entry: map.entrySet()) { key = entry.getKey(); }
2.2.3 遍历value
keySet遍历value(写法1):
Iterator<String> iter = map.keySet().iterator(); while (iter.hasNext()) { value = map.get(iter.next()); }
keySet遍历value(写法2):
for (String key : map.keySet()) { value = map.get(key); }
entrySet遍历value(写法1):
Iterator<Entry<String, String>> iter = map.entrySet().iterator(); while (iter.hasNext()) { value = iter.next().getValue(); }
entrySet遍历value(写法2):
for (Entry<String, String> entry: map.entrySet()) { value = entry.getValue(); }
values遍历value(写法1):
Iterator<String> iter = map.values().iterator(); while (iter.hasNext()) { value = iter.next(); }
values遍历value(写法2):
for (String value : map.values()) { }
2.3 测试结果
2.3.1 HashMap测试结果
单位:毫秒 |
HashMap-1 |
HashMap-2 |
keySet遍历key+value(写法1) |
39 |
93 |
keySet遍历key+value(写法2) |
38 |
87 |
entrySet遍历key+value(写法1) |
43 |
86 |
entrySet遍历key+value(写法2) |
43 |
85 |
单位:毫秒 |
HashMap-1 |
HashMap-2 |
keySet遍历key(写法1) |
27 |
65 |
keySet遍历key(写法2) |
26 |
64 |
entrySet遍历key(写法1) |
35 |
75 |
entrySet遍历key(写法2) |
34 |
74 |
单位:毫秒 |
HashMap-1 |
HashMap-2 |
keySet遍历value(写法1) |
38 |
87 |
keySet遍历value(写法2) |
37 |
87 |
entrySet遍历value(写法1) |
34 |
61 |
entrySet遍历value(写法2) |
32 |
62 |
values遍历value(写法1) |
26 |
48 |
values遍历value(写法2) |
26 |
48 |
2.3.2 TreeMap测试结果
单位:毫秒 |
TreeMap-1 |
TreeMap-2 |
keySet遍历key+value(写法1) |
430 |
451 |
keySet遍历key+value(写法2) |
429 |
450 |
entrySet遍历key+value(写法1) |
77 |
84 |
entrySet遍历key+value(写法2) |
70 |
68 |
单位:毫秒 |
TreeMap-1 |
TreeMap-2 |
keySet遍历key(写法1) |
50 |
49 |
keySet遍历key(写法2) |
49 |
48 |
entrySet遍历key(写法1) |
66 |
64 |
entrySet遍历key(写法2) |
65 |
63 |
单位:毫秒 |
TreeMap-1 |
TreeMap-2 |
keySet遍历value(写法1) |
432 |
448 |
keySet遍历value(写法2) |
430 |
448 |
entrySet遍历value(写法1) |
62 |
61 |
entrySet遍历value(写法2) |
62 |
61 |
values遍历value(写法1) |
46 |
46 |
values遍历value(写法2) |
45 |
46 |
3. 结论
3.1 如果你使用HashMap
- 同时遍历key和value时,keySet与entrySet方法的性能差异取决于key的具体情况,如复杂度(复杂对象)、离散度、冲突率等。换言之,取决于HashMap查找value的开销。entrySet一次性取出所有 key和value的操作是有性能开销的,当这个损失小于HashMap查找value的开销时,entrySet的性能优势就会体现出来。例如上述对比测试中,当key是最简单的数值字符串时,keySet可能反而会更高效,耗时比entrySet少10%。总体来说还是推荐使用entrySet。因为当key很简单时,其性能或许会略低于keySet,但却是可控的;而随着key的复杂化,entrySet的优势将会明显体现出来。当然,我们可以根据实际情况进行选择
- 只遍历key时,keySet方法更为合适,因为entrySet将无用的value也给取出来了,浪费了性能和空间。在上述测试结果中,keySet比entrySet方法耗时少23%。
- 只遍历value时,使用vlaues方法是最佳选择,entrySet会略好于keySet方法。
- 在不同的遍历写法中,推荐使用如下写法,其效率略高一些:
for (String key : map.keySet()) { value = map.get(key); }
for (Entry<String, String> entry: map.entrySet()) { key = entry.getKey(); value = entry.getValue(); }
for (String value : map.values()) { }
3.2 如果你使用TreeMap
- 同时遍历key和value时,与HashMap不同,entrySet的性能远远高于keySet。这是由TreeMap的查询效率决定的,也就是说,TreeMap查找value的开销较大,明显高于entrySet一次性取出所有key和value的开销。因此,遍历TreeMap时强烈推荐使用entrySet方法。
- 只遍历key时,keySet方法更为合适,因为entrySet将无用的value也给取出来了,浪费了性能和空间。在上述测试结果中,keySet比entrySet方法耗时少24%。
- 只遍历value时,使用vlaues方法是最佳选择,entrySet也明显优于keySet方法。
- 在不同的遍历写法中,推荐使用如下写法,其效率略高一些:
for (String key : map.keySet()) { value = map.get(key); }
for (Entry<String, String> entry: map.entrySet()) { key = entry.getKey(); value = entry.getValue(); }
for (String value : map.values()) { }
相关推荐
在工具使用方面,`Map`的遍历常用于数据处理、日志记录、调试和测试等场景。例如,`myeclipse.doc`可能是篇关于MyEclipse集成开发环境如何利用这些遍历技巧进行代码调试或数据可视化展示的文档。在源码分析时,了解...
Java Map的遍历方式在实际应用中是一个重要的性能优化考虑因素。常见的遍历方式有三种:keySet、entrySet和values。很多开发者推荐使用entrySet,认为它比keySet更高效,因为entrySet能一次性获取键值对,避免了额外...
JAVA遍历Map所有元素 JAVA语言中,Map是一种非常常用的数据结构,用于存储键值对。然而,在遍历Map中的所有元素时,我们需要使用合适的方法来提高效率。本文将对JAVA中遍历Map所有元素的两种常用方法进行详细介绍。...
在Java编程中,Map接口是用于存储键值对的数据结构,而Java提供了多种Map的实现,包括TreeMap、HashMap和ConcurrentSkipListMap。...在实际使用中,应结合性能测试和业务需求来确定最适合的Map类型。
在Java编程中,遍历大容量的Map是一个常见的操作,特别是在处理大数据或内存优化的场景下,选择正确的遍历方式至关重要。以下是对标题和描述中提及的四种遍历Map方法的详细说明: 1. **通过Map.keySet遍历key和...
性能测试及对比 为了比较这三种遍历方式的性能,我们进行了一些测试。测试环境如下: * Windows7 32位系统 * 3.2G双核CPU * 4G内存 * Java 7 * Eclipse * -Xms512m -Xmx512m 测试结果如下: | 遍历方式 | map ...
在性能测试中,`entrySet`通常表现最好,尤其是在处理大量数据时。而`keySet`和`values`在特定场景下有其优势。使用`Iterator`可以避免`ConcurrentModificationException`,但代码相对复杂。`Lambda表达式`简化了...
在Java中实现行转列,通常涉及数据结构的转换,如从List<List<String>>转换为List,或者更复杂地,从Map, Object>到自定义对象的集合。以下是一些关键知识点: 1. 数据结构理解: - **List**: Java中的List接口...
本文将详细介绍两种常见的遍历Map的方法,并通过性能测试进行对比。 一、遍历Map的方法 1. 方法A: ```java Map map = new HashMap(); Iterator iter = map.entrySet().iterator(); while (iter.hasNext()) { Map...
3. Map遍历方式:迭代器(Iterator)遍历、键集(keySet)遍历、入口集(entrySet)遍历。 4. HashMap、TreeMap和LinkedHashMap的区别与使用场景。 5. 泛型在Map中的应用:如何创建指定类型的Map实例。 6. Map与集合...
【北大高科Java测试题详解】 Java编程语言作为软件开发领域的主流工具,其深度和广度都相当广泛。北大高科的Java测试题通常涵盖了Java基础、面向对象编程、集合框架、异常处理、多线程、输入/输出(I/O)、网络编程、...
JDK (Java Development Kit) 提供了完整的 Java 开发环境,包括 Java 编译器(javac)、Java 运行环境(JRE)、以及各种开发工具,如 Javadoc(生成文档)和 JUnit(单元测试)。JRE (Java Runtime Environment) 则...
在开发过程中,还可以考虑引入第三方库,如`pinyin4j`,这些库已经实现了汉字转拼音的功能,并且经过了广泛的测试和优化,可以更方便地集成到项目中。 总的来说,Java中实现汉字转拼音涉及对码表文件的处理、拼音...
3. **集合框架**:List、Set、Map接口的实现类,如ArrayList、LinkedList、HashSet、HashMap等的区别和使用场景,以及遍历、查找、排序等操作。 4. **多线程**:Java线程的创建方式(Thread类和Runnable接口),...
每个文件"5.0_S1_Java内部测试机试题2.doc"、"5.0_S1_Java内部测试机试题3.doc"、"5.0_S1_Java内部测试机试题1.doc"都可能包含上述一个或多个知识点的测试题目,而"答案.java"则提供了解答,方便考生核对和学习。...
总结,Java读取Excel并进行数据库建库建表及生成Java实体的过程涉及了Apache POI库的使用、数据库操作和源代码生成。理解这些步骤可以帮助你有效地处理类似的任务,提高开发效率。在实际应用中,你还需要考虑错误...
例如,导入时,我们打开文件,遍历每一行和单元格,将数据存储到合适的数据结构(如List、Map或自定义对象);导出时,我们则根据数据填充Excel工作表。 2. **XML数据导入导出**: XML是一种结构化数据格式,广泛...