Map实现包括HashMap、TreeMap、LinkedHashMap、HashTable等。
Map的遍历,现在普遍提到的有4种方式:
- 1、使用entries+foreach(最常用)
这里以key和value分别为int和String来举例:
Map< Integer, String > mMap = new HashMap<>();
for (Map.Entry< Integer, String > entry : mMap.entrySet()) {
Log.d(TAG, "KEY = " + entry.getKey() + "; VALUE = " + entry.getValue());
}
注意:使用时,要检查遍历前mMap不为空。
- 2、使用keySet+foreach或者values+foreach(只需要键或值)
Map< Integer, String > mMap = new HashMap<>();
for (Integer key : mMap.keySet()) {
Log.d(TAG, "KEY = " + key );
}
for (String value : mMap.values()) {
Log.d(TAG, " VALUE = " + value);
}
比方法一速度快10%。
- 3、使用Iterator遍历(兼容低版本,可遍历时删除)
- 使用泛型
•
Map< Integer, String > mMap = new HashMap<>();
Iterator < Map.Entry< Integer, String >> entries = mMap.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry< Integer, String > entry = entries.next();
Log.d(TAG, “KEY = ” + entry.getKey() + “; VALUE = ” + entry.getValue());
}
- 不使用泛型(获取值时强转)
•
Map mMap = new HashMap();
Iterator entries = mMap.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry entry = (Map.Entry)entries.next();
Integer key = (Integer)entry.getKey();
Integer value = (Integer)entry.getValue();
Log.d(TAG, “KEY = ” + key + “; VALUE = ” + value);
}
方法三兼容老版本,可以调用iterator.remove()来删除键值对.
- 4、通过键找值(效率低的笨方法,注意不同于方法二)
Map< Integer, String > mMap = new HashMap<>();
for (Integer key : mMap.keySet()) {
Integer value = map.get(key);
Log.d(TAG, "KEY = " + key + "; VALUE = " + value);
}
通过键取值是很耗时的操作,与方法一比起来,方法四慢了20%-200%。
tips: 如果安装了FindBugs,能检出哪些是效率低的遍历,(相信过去这么多年,还有很多类似FindBugs的辅助工具)。
数据说话最有实力,这篇文章中
给出了测试对比。
以100万个item的HashMap和TreeMap做测试,分遍历key+value,遍历key,遍历value三种场景,这里仅贴出结论:
–> 如果使用HashMap
同时遍历key和value时,keySet和entrySet方法的性能差异取决于key的复杂度、离散度、冲突率等,换言之,HashMap查找value的开销。
entrySet一次性取出所有key和value的操作是有性能开销的,当这个损失小于HashMap查找value的开销,keySet的性能优势就会体现出来。
当key是简单的数值字符串,使用keySet获取value反而更高效,但当key更离散和复杂,耗时就更多了。因此总体看根据entrySet获取键值更可控。
–> 如果使用TreeMap
同时遍历key和value时,与HashMap不同,entrySet性能远高于keySet,因为TreeMap根据key查找value的开销较大,明显高于entrySet一次性获取所有key和value的开销。
若只需要遍历key,则用keySet,因为entrySet将无用的value也取出来了,浪费了性能和空间。
若只需要遍历value,则用values。
写法上,推荐foreach的写法。更简洁美观。
文末Trinea的两篇总结也附带了测试数据比对,没有仔细看。大家在原理总结方面,大同小异,总结的时间集中在2013年,估计是2010年这一块还没发展成熟。真实效率比对,需要我在实际项目中去用。
数据结构和算法是很重要的,数据结构就好像砖头、塑料、木材、纸张,虽然不同的东西可以实现一样的功能,但是效率、实现复杂度等各有差别,使用恰当的数据结构,配合恰当的算法逻辑,事半功倍。