Java Map遍历

作者: LY丶Smile | 来源:发表于2019-02-14 17:24 被阅读56次

    获取Keys

    public static void getKeys(Map<String, Object> map) {
            for(String key : map.keySet()) {
                printf(key);
            }
    }
    

    获取values

    public static void getValues(Map<String, Object> map) {
        for(Object value : map.values()) {
            printf(value);
        }
    }
    

    用entrySet获取key和value,遍历时不能移除元素,map大小发生变化就会报错

    public static void getKeyAndValue(Map<String, Object> map) {
        for(Map.Entry<String, Object> entry : map.entrySet()) {
            printf("key is " + entry.getKey() + " and value is " + entry.getValue());
        }
    }
    

    Iterator方式获取key和value,支持在遍历的时候删除元素

    public static void getKeyAndValueByIterator(Map<String, Object> map) {
        Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
        while(iterator.hasNext()) {
            Map.Entry<String, Object> entry = iterator.next();
            printf("key is " + entry.getKey() + " and value is " + entry.getValue());
            // 移除元素不会报错
            iterator.remove();
        }
    }
    

    Java 8 以后支持Lambda表达式,代码比较简洁帅气

    // Java 8 Lambda    
    public static void getKeyAndValueByLambda(Map<String, Object> map) {
        map.forEach((key, value) -> {
            printf("key is " + key + " and value is " + value);
        });
    }
    

    下面是map.forEach源码,其实也是使用的EntrySet

    default void forEach(BiConsumer<? super K, ? super V> action) {
        Objects.requireNonNull(action);
        for (Map.Entry<K, V> entry : entrySet()) {
            K k;
            V v;
            try {
                k = entry.getKey();
                v = entry.getValue();
            } catch(IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }
            action.accept(k, v);
        }
    }
    

    简单的性能测试

    10万条数据测试结果,单位:毫秒

    10万数据量

    100万条数据测试结果,单位:毫秒

    100万数据量

    1000万条数据测试结果,单位:毫秒


    image.png

    2000万条数据测试结果,单位:毫秒


    image.png

    只是简单的统计了下遍历时间

    • 如果需要获取KV,不建议使用keySet,keySet是遍历两次才能拿到KV,第一次遍历取Key,然后根据Key拿Value
    • Lambda形式,代码写出来比较漂亮。
    • 数据量很大的话使用最基础的EntrySet即可,对应getKeyAndValue 优先保证性能
    • 如果需要遍历时移除元素,使用getKeyAndValueByIterator

    着重说明下Lambda表达式,因为新特性耗费时间更长了,很费解,就多测了几遍,也查了一些资料,发现了一些好东西

    Lambda是多线程遍历的,但是启动的时候会比较慢(类似要初始化),所以数据量级上来之后,Lambda表达式形式的遍历优势就体现出来了。

    比如:从100万的数据量到1000万的数据量,发现getKeyAndValuegetKeyAndValueByIterator耗费时间接近翻倍,但是Lambda形式耗费时间是缩了一倍(数据不精确,只是大致,但是百万到千万数据量的变化上,getKeyAndValueByLambda耗费时间是很明显缩短了的)

    源码

    public class MyMapTest {
    
        public static Map<String, Object> map = new HashMap<>(8);
        
        public static void main(String[] args) {
            // 测试数据,key和value随机生成
            for(int i = 0; i < 1000000; i++) {
                map.put(getRandomStrBylen(4), getRandomStrBylen(8));
            }
            
            long start = System.currentTimeMillis();
            getKeys(map);
            long end = System.currentTimeMillis();
            printf("getKeys耗费时间:" + calculation(start, end));
            
            start = System.currentTimeMillis();
            getValues(map);
            end = System.currentTimeMillis();
            printf("getValues耗费时间:" + calculation(start, end));
            
            start = System.currentTimeMillis();
            getKeyAndValue(map);
            end = System.currentTimeMillis();
            printf("getKeyAndValue耗费时间:" + calculation(start, end));
            
            start = System.currentTimeMillis();
            getKeyAndValueByIterator(map);
            end = System.currentTimeMillis();
            printf("getKeyAndValueByIterator耗费时间:" + calculation(start, end));
            
            start = System.currentTimeMillis();
            getKeyAndValueByLambda(map);
            end = System.currentTimeMillis();
            printf("getKeyAndValueByLambda耗费时间:" + calculation(start, end));
        }
        
        
        public static void getKeys(Map<String, Object> map) {
            for(String key : map.keySet()) {
    //          printf(key);
                ;
            }
        }
        
        public static void getValues(Map<String, Object> map) {
            for(Object value : map.values()) {
    //          printf(value);
                ;
            }
        }
        
        public static void getKeyAndValue(Map<String, Object> map) {
            for(Map.Entry<String, Object> entry : map.entrySet()) {
    //          printf("key is " + entry.getKey() + " and value is " + entry.getValue());
                ;
            }
        }
        
        // 支持在遍历的时候删除元素
        public static void getKeyAndValueByIterator(Map<String, Object> map) {
            Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
            while(iterator.hasNext()) {
                Map.Entry<String, Object> entry = iterator.next();
    //          printf("key is " + entry.getKey() + " and value is " + entry.getValue());
                ;
                // 移除元素不会报错
    //          iterator.remove();
            }
        }
        
        // Java 8 Lambda    
        public static void getKeyAndValueByLambda(Map<String, Object> map) {
            map.forEach((key, value) -> {
    //          printf("key is " + key + " and value is " + value);
                ;
            });
        }
        
        
        private static void printf(Object obj) {
            System.out.println(String.valueOf(obj));
        }
        
        private static long calculation(long start, long end) {
            return end - start;
        }
        
        /**
         * 获取指定长度的随机字符串
         * @param length  字符串长度
         * @return
         */
        private static String getRandomStrBylen(Integer length){
            String base = "abcdefghijklmnopqrstuvwxyz0123456789";
            Random random = new Random();
            StringBuilder sb = new StringBuilder();
            for(int i = 0;i < length;i++){
                int number = random.nextInt(base.length());
                sb.append(base.charAt(number));
            }
            return sb.toString();
        }
    }

    相关文章

      网友评论

        本文标题:Java Map遍历

        本文链接:https://www.haomeiwen.com/subject/wameeqtx.html