HashMap中keySet和entrySet的区别
theme: cyanosis
今天进行CR的时候,发现代码中对HashMap进行遍历时,使用的是for(key in map.keys)
,就想起了之前看到的一个文章,说使用entrySet()
进行遍历性能更高。当时没有追究,但是最近看《代码整洁之道》,学到了
勒布朗(LeBlanc)法则:稍后等于永不(Later equals never)
那么今天一定要把其中的原理搞清楚。
用法
-
keySet()
for (key in map.keys) { map[key] }
-
entrySet()
for (entry in map.entries) { entry.value }
差异
-
keySet()返回的是一个关于K的Set (第一次查询),要获取value,还需要通过map[key]获取 (第二步查询)。
-
entrySet()返回的是一个K,V键值对的Set (第一次查询),获取value直接调用entry.value (不需要查询)。
思考
- 虽然使用
entrySet()
进行遍历,性能更好,但是多线程下就没办法保证安全性了,所以在多线程情况下,建议考虑使用ConcurrentHashMap()
。 - 观察
entrySet()
方法,发现entrySet
为null
时,返回的是EntrySet()
对象,但是看EntrySet
源码,构造方法是空实现,那数据从哪里来的呢?先看下源码:
```
public Set
final class EntrySet extends AbstractSet``
可以发现
iterator()方法返回了
EntryIterator()对象,深入其中,发现其继承了
HashIterator,而
HashIterator构造方法则是从关联到了
table,在
HashMap的put方法中,就是向
table`中插入值。
可能有人会问,这与EntrySet()
有什么关系呢?for
循环怎么获取到的Set
对象呢?
通过对kotlin
代码转成Bytecode
,再反编译成java
语言,可以发现:
```
var3 = map.entrySet().iterator();
while(var3.hasNext()) {
Map.Entry entry = (Map.Entry)var3.next();
entry.getValue();
}
``
就是说
for (entry in map.entries),实际上是遍历的迭代器,这就与前面
EntrySet的
iterator()`方法的返回值关联起来了,突然想起了名侦探柯南的画面,哈哈哈