Java Map遍历

获取Keys

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

获取values

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

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

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

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

public static void getKeyAndValueByIterator(Map map) {
    Iterator> iterator = map.entrySet().iterator();
    while(iterator.hasNext()) {
        Map.Entry 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 map) {
    map.forEach((key, value) -> {
        printf("key is " + key + " and value is " + value);
    });
}

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

default void forEach(BiConsumer action) {
    Objects.requireNonNull(action);
    for (Map.Entry 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万条数据测试结果,单位:毫秒

Java Map遍历_第1张图片
10万数据量

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

Java Map遍历_第2张图片
100万数据量

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


Java Map遍历_第3张图片
image.png

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


Java Map遍历_第4张图片
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 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 map) {
        for(String key : map.keySet()) {
//          printf(key);
            ;
        }
    }
    
    public static void getValues(Map map) {
        for(Object value : map.values()) {
//          printf(value);
            ;
        }
    }
    
    public static void getKeyAndValue(Map map) {
        for(Map.Entry entry : map.entrySet()) {
//          printf("key is " + entry.getKey() + " and value is " + entry.getValue());
            ;
        }
    }
    
    // 支持在遍历的时候删除元素
    public static void getKeyAndValueByIterator(Map map) {
        Iterator> iterator = map.entrySet().iterator();
        while(iterator.hasNext()) {
            Map.Entry entry = iterator.next();
//          printf("key is " + entry.getKey() + " and value is " + entry.getValue());
            ;
            // 移除元素不会报错
//          iterator.remove();
        }
    }
    
    // Java 8 Lambda    
    public static void getKeyAndValueByLambda(Map 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遍历)