Java Map遍歷

獲取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大小發(fā)生變化就會報錯

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表達(dá)式,代碼比較簡潔帥氣

// 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萬條數(shù)據(jù)測試結(jié)果,單位:毫秒

10萬數(shù)據(jù)量

100萬條數(shù)據(jù)測試結(jié)果,單位:毫秒

100萬數(shù)據(jù)量

1000萬條數(shù)據(jù)測試結(jié)果,單位:毫秒


image.png

2000萬條數(shù)據(jù)測試結(jié)果,單位:毫秒


image.png

只是簡單的統(tǒng)計了下遍歷時間

  • 如果需要獲取KV,不建議使用keySet,keySet是遍歷兩次才能拿到KV,第一次遍歷取Key,然后根據(jù)Key拿Value
  • Lambda形式,代碼寫出來比較漂亮。
  • 數(shù)據(jù)量很大的話使用最基礎(chǔ)的EntrySet即可,對應(yīng)getKeyAndValue 優(yōu)先保證性能
  • 如果需要遍歷時移除元素,使用getKeyAndValueByIterator

著重說明下Lambda表達(dá)式,因為新特性耗費時間更長了,很費解,就多測了幾遍,也查了一些資料,發(fā)現(xiàn)了一些好東西

Lambda是多線程遍歷的,但是啟動的時候會比較慢(類似要初始化),所以數(shù)據(jù)量級上來之后,Lambda表達(dá)式形式的遍歷優(yōu)勢就體現(xiàn)出來了。

比如:從100萬的數(shù)據(jù)量到1000萬的數(shù)據(jù)量,發(fā)現(xiàn)getKeyAndValuegetKeyAndValueByIterator耗費時間接近翻倍,但是Lambda形式耗費時間是縮了一倍(數(shù)據(jù)不精確,只是大致,但是百萬到千萬數(shù)據(jù)量的變化上,getKeyAndValueByLambda耗費時間是很明顯縮短了的)

源碼

public class MyMapTest {

    public static Map<String, Object> map = new HashMap<>(8);
    
    public static void main(String[] args) {
        // 測試數(shù)據(jù),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();
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容