阿里巴巴建議這樣遍歷Map,今天就用幾種方式做個比較一下看那種最好用

程式設計師xiaozhang發表於2023-04-09

​今天不舉例子了,問一句你開心嗎?不開心也要記得把開心的事情放到快樂源泉小瓶子裡,偶爾拿出來一一遍歷看看。

Map在我們Java程式設計師高頻使用的一種資料結構,Map的遍歷方式也有很多種,那那種方式比較高效呢,今天就帶大家一起驗證下。

先說一下阿里巴巴Java開發手冊的建議:

【推薦】使用entrySet遍歷Map類集合K/V,而不是用keySet方式遍歷。 

說明:keySet其實遍歷了2次,一次是轉換為Iterator物件,另一次是從hashMap種取出key對應的value。如果是JDK8,使用Map.forEash方法。

1:透過for和map.entrySet()方式遍歷。

// Map初始化
 private  static Map<String,Integer> initMap(int count){
        AlternativeJdkIdGenerator alternativeJdkIdGenerator = new AlternativeJdkIdGenerator();
        Map<String,Integer> map = new HashMap<>();
        for (int i = 0; i < count; i++) {
            map.put(alternativeJdkIdGenerator.generateId().toString(),i) ;
        }
        return  map ;
    }
int count = 1000000;
        Map<String,Integer> map =initMap(count) ;
        // 為了計算平均值,分別迴圈三次進行遍歷
        for (int i = 0; i < 3; i++) {
            Instant start;
            Instant end;
            start = Instant.now();
            for (Map.Entry<String, Integer> entry : map.entrySet()) {
                // 一般遍歷map就是獲取key和value
                String  result="key為:"+entry.getKey()+",value為:"+entry.getValue();
            }
            end = Instant.now();
            System.out.println("遍歷迴圈" + count + "次耗時:" + Duration.between(start, end).toMillis() + "ms");
        }

執行三次的結果如下:(平均值:368.33ms)

 

​2、透過 for, Iterator 和 map.entrySet() 來遍歷

  int count = 1000000;
        Map<String,Integer> map =initMap(count) ;
        for (int i = 0; i < 3; i++) {
            Instant start;
            Instant end;
            start = Instant.now();
            for (Iterator<Map.Entry<String,Integer>> entries = map.entrySet().iterator(); entries.hasNext(); ) {
                Map.Entry<String,Integer> entry = entries.next();
                String result ="key為:"+entry.getKey()+",value為:"+entry.getValue();
            }
            end = Instant.now();
            System.out.println("遍歷迴圈" + count + "次耗時:" + Duration.between(start, end).toMillis() + "ms");
        }

​執行三次的結果如下:(平均值:339.66ms)

 

 

 ​3、透過 for 和 map.keySet() 來遍歷

 int count = 1000000;
        Map<String,Integer> map =initMap(count) ;
        for (int i = 0; i < 3; i++) {
            Instant start;
            Instant end;
            start = Instant.now();
            for (String key : map.keySet()) {
                String result ="key為:"+key+",value為:"+map.get(key);
            }
            end = Instant.now();
            System.out.println("遍歷迴圈" + count + "次耗時:" + Duration.between(start, end).toMillis() + "ms");
        }

執行三次的結果如下:(平均值:379.66ms)

​4、透過 for,Iterator 和 map.keySet() 來遍歷

  int count = 1000000;
        Map<String,Integer> map =initMap(count) ;
        for (int i = 0; i < 3; i++) {
            Instant start;
            Instant end;
            start = Instant.now();
            for (Iterator<String> key = map.keySet().iterator(); key.hasNext(); ) {
                String k = key.next();
                String result ="key為:"+k+",value為:"+map.get(k);
            }
            end = Instant.now();
            System.out.println("遍歷迴圈" + count + "次耗時:" + Duration.between(start, end).toMillis() + "ms");
        }

執行三次的結果如下:(平均值330.33ms)

 

 5、透過 map.forEach() 來遍歷

int count = 1000000;
        Map<String,Integer> map =initMap(count) ;
        for (int i = 0; i < 3; i++) {
            Instant start;
            Instant end;
            start = Instant.now();
            map.forEach((key, value) -> {
                String result ="key為:"+key+",value為:"+map.get(value);
            });
            end = Instant.now();
            System.out.println("遍歷迴圈" + count + "次耗時:" + Duration.between(start, end).toMillis() + "ms");
        }

​執行三次的結果如下:(平均值506.33ms)

 

 

​經過上面的驗證(在大批次資料的時候,資料量小的時候沒測試,感覺資料量小的化耗時太小更不好比較)最好不要用map.forEach()來遍歷Map。在普通的遍歷方法中 entrySet() 的方法要比使用 keySet() 的方法好。【PS雖然keySet() 的平均值有時候比較小,但它的波動性比較大,所以還是考慮阿里巴巴Java開發手冊的建議使用entrySet()遍歷Map】。

看過 HashMap 原始碼的同學應該會發現,這個遍歷方式【entrySet(】在原始碼中也有使用,如下圖所示。

 

 

 ​Spring的原始碼也有很多的Map,大神們遍歷的方式也都基本使用entrySet()遍歷如下:

 

 所以開發中也建議使用entrySet()來遍歷Map。

相關文章