zoukankan      html  css  js  c++  java
  • 常用遍历hashMap的方法对效率的影响

    测试环境:jdk1.7.0_79Processor 1.7 GHz Intel Core i5

    遍历Map的方式有很多,通常场景下我们需要的是遍历Map中的Key和Value。

    更新:增加一个方法对方法一优化,采用foreach循环

    写了四个方法:

        /**

         * while循环 map.entrySet().iterator()获取map的value

         * @param map

         */

        public static void getMap1(Map<String,String> map){

        Iterator<Map.Entry<String, String>> iter = map.entrySet().iterator();

            while (iter.hasNext()) {

                Map.Entry<String, String> entry = iter.next();

                String key = entry.getKey();

                String value = entry.getValue();

            }

        }

        

        /**

         * while循环 map.keySet().iterator()获取map的value

         * @param map

         */

        public static void getMap2(Map<String,String> map){

        Iterator<String> it = map.keySet().iterator();

            while (it.hasNext()) {

                String key = it.next();

                String value = map.get(key);

            }

        }

        /**

         * foreach循环map.entrySet()获取map的value

         * getMap1的另一种写法,采用foreach循环.foreach循环的底层实现原理就是迭代器Iterator

         * @param map

         */

        public static void getMap3(Map<String,String> map){

            Set<Map.Entry<String, String>> set = map.entrySet();

            for (Map.Entry<String, String> entry : set) {

                String value = entry.getValue();

                }

        }

        /**

         * foreach循环map.keySet()获取map的value

         * @param map

         */

        public static void getMap4(Map<String,String> map){

        Set<String> set = map.keySet();

        for (String entry : set) {

        String value = map.get(entry);

        }

        }

    注:我以前常用的就是方法2,原则就是能用就行。所以第一印象不一定对哦。

    默认map中已经存储了数据,map数据量不确定,用户访问量不确定

    我采用for循环多次调用getMap方法来模拟用户访问,如下:

     

          HashMap<String, String> map = new HashMap<String, String>();

            int mapNum=1000;//设置map数据量

            int forNum = 1000;//设置for循环调用次数,模拟用户访问次数

            //模拟map已经存储了数据

            for (int i = 0; i < mapNum; i++) {

                map.put("key" + i, "value" + i);

            }

            //用for循环调用getMap来模拟多次访问

            long startTime = System.currentTimeMillis();

            for (int i = 0; i < forNum; i++) {

                getMap1(map);

            }

            System.out.println("getMap1:"+(System.currentTimeMillis() - startTime) + "ms");

     

            startTime = System.currentTimeMillis();

            for (int i = 0; i < forNum; i++) {

                getMap2(map);

            }

            System.out.println("getMap2:"+(System.currentTimeMillis() - startTime) + "ms");

            

            startTime = System.currentTimeMillis();

            for (int i = 0; i < forNum; i++) {

                getMap3(map);

            }

            System.out.println("getMap3:"+(System.currentTimeMillis() - startTime) + "ms");

            startTime = System.currentTimeMillis();

            for (int i = 0; i < forNum; i++) {

            getMap4(map);

            }

            System.out.println("getMap4:"+(System.currentTimeMillis() - startTime) + "ms");

     

    (以下测试数据是前三个方法的数据,方法四也类似的结果) 

    map数据量为10,用户访问10次(for循环调用getMap 10次)

    看不出来效果

    map数据量为10,用户访问100次(for循环调用getMap 100次)

    看不出来效果

    map数据量为10,用户访问1000次(for循环调用getMap 1000次)

    getMap1:15ms

    getMap2:22ms

    getMap3:4ms

    map数据量为10,用户访问10000次(for循环调用getMap 10000次)

    getMap1:27ms

    getMap2:31ms

    getMap3:15ms

    map数据量为10,用户访问100000次(for循环调用getMap 10万次)

    getMap1:52ms

    getMap2:53ms

    getMap3:32ms

    map数据量为10,用户访问1000000次(for循环调用getMap 百万次)

    getMap1:169ms

    getMap2:280ms

    getMap3:128ms

    百万级别的时候差距拉大了,但有时候1和3差距不大

    map数据量为100,for循环调用getMap 100次

    getMap1:8ms

    getMap2:18ms

    getMap3:4ms

    一倍差距啊

    map数据量为100,for循环调用getMap 1000次

    getMap1:23ms

    getMap2:28ms

    getMap3:14ms

    map数据量为100,for循环调用getMap 1万次

    getMap1:38ms

    getMap2:57ms

    getMap3:28ms

    map数据量为100,for循环调用getMap 10万次

    getMap1:126ms

    getMap2:221ms

    getMap3:75ms

    map数据量为100,for循环调用getMap 百万次

    getMap1:641ms

    getMap2:1823ms

    getMap3:574ms

    1和2三倍啊!,不过这个时候1和3差距不大了

    后面仅仅是摘选几条:

    map数据量为1000,for循环调用getMap 1000次

    getMap1:44ms

    getMap2:43ms

    getMap3:26ms

     

    map数据量为1000,for循环调用getMap 是万次

    getMap1:1259ms

    getMap2:2420ms

    getMap3:887ms

    map数据量为1000,for循环调用getMap 百万次

    getMap1:11210ms

    getMap2:21083ms

    getMap3:6941ms

    map数据量为10000,for循环调用getMap 10000次

    getMap1:2807ms

    getMap2:4770ms

    getMap3:2511ms

    map数据量为10000,for循环调用getMap 百万次

    getMap1:167107ms

    getMap2:230967ms

    getMap3:123263ms

     

     

     

    基本上方法一的效率和四差不多,比方法二高一倍,方法三比方法一效率高一些,建议采用方法三当然实际情况可能很复杂,硬件设备、并发情况,更多的时候仅仅是map数据量大但是访问量小,甚至可能我们采用服务器启动即加载的方式避免了用户访问时遍历。

    而且要注意,不同情况下的写法不同,测试结果可能是不一样的。需要注重的是,一旦涉及到遍历的情况,就要考虑数据量和访问量,来选择最佳的遍历方式。

     

     

    顺便提一句:有些人可能习惯这样写代码

    for(int i = 0;i < list.length();i++){}以及foreach语句,我印象中for循环中每次都要计算一次list.length,这也是不必要的开销。foreach在顺序访问中效率高,所以如果是遍历arrayList的时候不要用foreach

     

     

    更新:如果只是想要遍历一下key呢?方法三不一定比方法二好,方法一肯定比方法二差。例如

    map数据量为10000,for循环调用getMap 10000次

     

     

    getMap1:2767ms

     

    getMap2:1068ms

     

    getMap3:2208ms

    根据实际情况选择吧。

     

     

    欢迎各位补充。

  • 相关阅读:
    【PHP内存泄漏案例】PHP对象递归引用造成内存泄漏
    【总结】/etc/rc.d/rc.local 与 /etc/profile .bash_profile .bashrc 文件执行顺序
    MySQL数据类型
    PHP通用分页(Pager)类
    【抚琴煮酒】我们的网站压力究竟在哪里?
    Linux/CentOS 服务安装/卸载,开机启动chkconfig命令详解|如何让MySQL、Apache开机启动?
    /etc/rc.d/rc与/etc/rc.d/init.d的关系
    PHP正则表达式30分钟入门教程
    数学之路-分布式计算-disco(4)
    数据库中存储日期的字段类型究竟应该用varchar还是datetime ?
  • 原文地址:https://www.cnblogs.com/javac/p/6415909.html
Copyright © 2011-2022 走看看