遍历HashMap的几种方式及其效率比较,HashMap删除元素时如何处理

首先,小测试代码:

package org.apache.camel.component.jdbc;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author yudk
 * @Date 2018/5/14
 */
public class Test {
    public static void main(String[] args){
        HashMap<Integer, String> map = new HashMap<Integer, String>();
        Map<Integer, String> map2 = new ConcurrentHashMap<>();
        for (int i=0; i<100000; i++){
            map.put(i, " No."+i);
            map2.put(i, " No."+i);
        }
        //第一种   for循环直接遍历
        long t1 = System.nanoTime();
        Object key[] = map.keySet().toArray();
        for (int i=0; i<map.size();i++){
            map.get(key[i]);
        }
        long t2 = System.nanoTime();
        //第二种 entrySet的for循环遍历
        for(Map.Entry<Integer, String> entry:map.entrySet()){
            entry.getValue();
        }
        long t3 = System.nanoTime();
        //第三种 entrySet的迭代器遍历
        Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
       while (iterator.hasNext()){
           Map.Entry<Integer, String> entry = iterator.next();
            entry.getValue();
        }
        long t4 = System.nanoTime();
        //第四种 迭代器遍历keySet()然后map.get(key)
        Iterator<Integer> it = map.keySet().iterator();
        while(it.hasNext()){
            Integer ii = (Integer)it.next();
            map.get(ii);
        }
        long t5 = System.nanoTime();
        //第五种 for循环遍历keySet(),然后Map.get(key)
        for (Integer kk :map.keySet()){
            map.get(kk);
        }
        long t6 = System.nanoTime();
        /***
                ConcurrentHashMap
         */
        //第一种   for循环直接遍历
        long t11 = System.nanoTime();
        Object key2[] = map2.keySet().toArray();
        for (int i=0; i<map2.size();i++){
            map2.get(key2[i]);
        }
        long t21 = System.nanoTime();
        //第二种 entrySet的for循环遍历
        for(Map.Entry<Integer, String> entry:map2.entrySet()){
            entry.getValue();
        }
        long t31 = System.nanoTime();
        //第三种 entrySet的迭代器遍历
        Iterator<Map.Entry<Integer, String>> iterator1 = map2.entrySet().iterator();
        while (iterator1.hasNext()){
            Map.Entry<Integer, String> entry = iterator1.next();
            entry.getValue();
        }
        long t41 = System.nanoTime();
        //第四种 迭代器遍历keySet()然后map.get(key)
        Iterator<Integer> it2 = map2.keySet().iterator();
        while(it2.hasNext()){
            Integer ii = (Integer)it2.next();
            map2.get(ii);
        }
        long t51 = System.nanoTime();
        //第五种 for循环遍历keySet(),然后Map.get(key)
        for (Integer kk :map2.keySet()){
            map2.get(kk);
        }
        long t61 = System.nanoTime();
        System.out.println("第一种方法 for循环直接遍历                     耗时:" + (t2-t1)/1000 + " 微秒"+"    ConcurrentHashMap   " + (t21-t11)/1000 + " 微秒");
        System.out.println("第二种方法 entrySet的for循环遍历               耗时:" + (t3-t2)/1000 + " 微秒"+"    ConcurrentHashMap   " + (t31-t21)/1000 + " 微秒");
        System.out.println("第三种方法 entrySet的迭代器遍历                耗时:" + (t4-t3)/1000 + " 微秒"+"    ConcurrentHashMap   " + (t41-t31)/1000 + " 微秒");
        System.out.println("第四种方法 迭代器遍历keySet()后map.get(key)    耗时:" + (t5-t4)/1000 + " 微秒"+"    ConcurrentHashMap   " + (t51-t41)/1000 + " 微秒");
        System.out.println("第五种方法 for循环遍历keySet()后Map.get(key)   耗时:" + (t6-t5)/1000 + " 微秒"+"    ConcurrentHashMap   " + (t61-t51)/1000 + " 微秒");
    }
}  

结果 : 

遍历Map的效率问题
测试代码:


10000000时
	第一种方法 for循环直接遍历                     耗时:276051微秒
	第二种方法 entrySet的for循环遍历               耗时:109980微秒
	第三种方法 entrySet的迭代器遍历                耗时:106750微秒
	第四种方法 迭代器遍历keySet()后map.get(key)    耗时:154363微秒
	第五种方法 for循环遍历keySet()后Map.get(key)   耗时:158439微秒

5000000时
	第一种方法 for循环直接遍历                     耗时:162365微秒
	第二种方法 entrySet的for循环遍历               耗时:65818微秒
	第三种方法 entrySet的迭代器遍历                耗时:63480微秒
	第四种方法 迭代器遍历keySet()后map.get(key)    耗时:82398微秒
	第五种方法 for循环遍历keySet()后Map.get(key)   耗时:81131微秒
1000000时
	第一种方法 for循环直接遍历                     耗时:46260微秒
	第二种方法 entrySet的for循环遍历               耗时:18332微秒
	第三种方法 entrySet的迭代器遍历                耗时:17057微秒
	第四种方法 迭代器遍历keySet()后map.get(key)    耗时:26546微秒
	第五种方法 for循环遍历keySet()后Map.get(key)   耗时:25695微秒
500000时
	第一种方法 for循环直接遍历                     耗时:31365微秒
	第二种方法 entrySet的for循环遍历               耗时:10434微秒
	第三种方法 entrySet的迭代器遍历                耗时:10249微秒
	第四种方法 迭代器遍历keySet()后map.get(key)    耗时:15557微秒
	第五种方法 for循环遍历keySet()后Map.get(key)   耗时:16032微秒


100000时
	第一种方法 for循环直接遍历                     耗时:16108微秒
	第二种方法 for循环遍历entrySet	               耗时:7081微秒
	第三种方法 迭代器遍历entrySet                  耗时:7539微秒
	第四种方法 迭代器遍历keySet()后map.get(key)    耗时:11451微秒
	第五种方法 for循环遍历keySet()后Map.get(key)   耗时:12468微秒

10000时
	第一种方法 for循环直接遍历                     耗时:3461微秒
	第二种方法 for循环遍历entrySet	               耗时:1887微秒
	第三种方法 迭代器遍历entrySet                  耗时:1170微秒
	第四种方法 迭代器遍历keySet()后map.get(key)    耗时:1562微秒
	第五种方法 for循环遍历keySet()后Map.get(key)   耗时:1479微秒

1000时
	第一种方法 for循环直接遍历                     耗时:603微秒
	第二种方法 for循环遍历entrySet	               耗时:356微秒
	第三种方法 迭代器遍历entrySet                  耗时:127微秒
	第四种方法 迭代器遍历keySet()后map.get(key)    耗时:153微秒
	第五种方法 for循环遍历keySet()后Map.get(key)   耗时:147微秒
100时
	第一种方法 for循环直接遍历                     耗时:487微秒
	第二种方法 for循环遍历entrySet	               耗时:426微秒
	第三种方法 迭代器遍历entrySet                  耗时:41微秒
	第四种方法 迭代器遍历keySet()后map.get(key)    耗时:44微秒
	第五种方法 for循环遍历keySet()后Map.get(key)   耗时:43微秒

10时
	第一种方法 for循环直接遍历                     耗时:342微秒
	第二种方法 for循环遍历entrySet	               耗时:360微秒
	第三种方法 迭代器遍历entrySet                  耗时:3微秒
	第四种方法 迭代器遍历keySet()后map.get(key)    耗时:5微秒
	第五种方法 for循环遍历keySet()后Map.get(key)   耗时:5微秒


结论:
     数据量为10000以下时,采用方法三四五差不多,即先遍历迭代器遍历EntrySet 与 KeySet的遍历取值 效率较高
     数据量为10000以上时,获取二三即for循环遍历entrySet 和 迭代器遍历entrySet 效率较高

     综上:迭代器遍历Map 在各个数量级效率稳定且较高,一般采用Iterator迭代器遍历Map.
    另外,当遍历Map需要删除的时候,不可以for循环遍历,否则会产生并发修改异常CME,只能使用迭代器iterator.remove()
	来删除元素,或者使用线程安全的concurrentHashMap来删除Map中删除元素(concurrentHashMap和迭代器Iterator遍历删除)

猜你喜欢

转载自blog.csdn.net/ydk888888/article/details/80107510