您的位置:首页 > 编程语言 > Java开发

java HashMap两种遍历方式的深入研究

2015-07-15 15:18 465 查看
HashMap的遍历有两种方式,如下所示:

第一种利用entrySet的方式:

Map map = new HashMap();
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Object key = entry.getKey();
Object val = entry.getValue();
}


上面的方式可以变化为for循环的形式:

Map<String, String> map = new HashMap<String, String>();
for (Entry<String, String> entry : map.entrySet()) {
entry.getKey();
entry.getValue();
}


第二种利用keySet的方式:

Map map = new HashMap();
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
Object key = iter.next();
Object val = map.get(key);
}


上面的方式也可以变化为for循环的形式:

Map<String, String> map = new HashMap<String, String>();
for (String key : map.keySet()) {
map.get(key);
}


这两种方式那种效率高呢?可以从下面的试验可以看出来:

public class Test
{
public static void main(String[] args)
{
HashMap<String, String> map = new HashMap<String, String>();
for (int i = 0; i < 1000000; i++)
{
map.put(i + "", "hello world");
}
long begin1 = System.currentTimeMillis();
Iterator iterator1 = map.entrySet().iterator();
while (iterator1.hasNext())
{
Map.Entry entry = (Map.Entry) iterator1.next();
Object key1 = entry.getKey();
Object val1 = entry.getValue();
}
long end1 = System.currentTimeMillis();
System.out.println("map.entrySet方式变量花费的时间为:" + (end1 - begin1));
long begin2 = System.currentTimeMillis();
Iterator iterator2 = map.keySet().iterator();
while (iterator2.hasNext())
{
Object key2 = iterator2.next();
Object val2 = map.get(key2);
}
long end2 = System.currentTimeMillis();
System.out.println("map.keySet方式变量花费的时间为:" + (end2 - begin2));
}
}


结论:

经过运行多次,我发现两者的运行时间相差不多,而且没有明确显示出那种变量方式更快一些。有的人可能会觉得第一种变量方式会快一些,因为他们觉得:keySet方式其实是遍历了2次,一次是转为iterator,一次就从HashMap中取出key所对应的value,而entry方式只遍历了一次,把key和value都放到了entry中,所以entry方式更快一些。

但是我觉得这种分析的方式比较主观,我们更应该从源码的角度去分析。首先看一下迭代器的源码:

keySet的迭代器:

private final class KeyIterator extends HashIterator<K> {
public K next() {
return nextEntry().getKey();
}
}


entrySet的迭代器:

private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
public Map.Entry<K,V> next() {
return nextEntry();
}
}


从上面我们可以看到只是返回值不同而已,父类相同,所以性能相差不多。下面我们再看一下get方法的源码:

public V get(Object key)
{
if (key == null)
return getForNullKey();
Entry<K, V> entry = getEntry(key);
return null == entry ? null : entry.getValue();
}


final Entry<K, V> getEntry(Object key)
{
int hash = (key == null) ? 0 : hash(key);
for (Entry<K, V> e = table[indexFor(hash, table.length)]; e != null; e = e.next)
{
Object k;
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}


从上面的源码发现get的时间复杂度取决于for循环循环次数,即hash算法。所以两种性能差别不大。从上面的分析来看,我们得到最终的结论:

(1)HashMap的循环,如果既需要key也需要value,直接用

Map<String, String> map = new HashMap<String, String>();
for (Entry<String, String> entry : map.entrySet()) {
entry.getKey();
entry.getValue();
}


即可,foreach简洁易懂。

(2)如果只是遍历key而无需value的话,可以直接用

Map<String, String> map = new HashMap<String, String>();
for (String key : map.keySet()) {
// key process
}


转载自:HashMap两种遍历方式的深入研究
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: