日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

阿里巴巴Java开发手册建议设置HashMap的初始容量,但设置多少合适呢?

發(fā)布時間:2025/3/11 java 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 阿里巴巴Java开发手册建议设置HashMap的初始容量,但设置多少合适呢? 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

作者 l Hollis

來源 l Hollis(ID:hollischuang)

集合是Java開發(fā)日常開發(fā)中經(jīng)常會使用到的,而作為一種典型的K-V結(jié)構(gòu)的數(shù)據(jù)結(jié)構(gòu),HashMap對于Java開發(fā)者一定不陌生。

關(guān)于HashMap,很多人都對他有一些基本的了解,比如他和hashtable之間的區(qū)別、他和concurrentHashMap之間的區(qū)別等。這些都是比較常見的,關(guān)于HashMap的一些知識點和面試題,想來大家一定了熟于心了,并且在開發(fā)中也能有效的應用上。

但是,作者在很多次 CodeReview 以及面試中發(fā)現(xiàn),有一個比較關(guān)鍵的小細節(jié)經(jīng)常被忽視,那就是HashMap創(chuàng)建的時候,要不要指定容量?如果要指定的話,多少是合適的?為什么?

要設(shè)置HashMap的初始化容量

在《HashMap中傻傻分不清楚的那些概念》中我們曾經(jīng)有過以下結(jié)論:

HashMap有擴容機制,就是當達到擴容條件時會進行擴容。HashMap的擴容條件就是當HashMap中的元素個數(shù)(size)超過臨界值(threshold)時就會自動擴容。在HashMap中,threshold = loadFactor * capacity。

所以,如果我們沒有設(shè)置初始容量大小,隨著元素的不斷增加,HashMap會發(fā)生多次擴容,而HashMap中的擴容機制決定了每次擴容都需要重建hash表,是非常影響性能的。

所以,首先可以明確的是,我們建議開發(fā)者在創(chuàng)建HashMap的時候指定初始化容量。并且《阿里巴巴開發(fā)手冊》中也是這么建議的:


HashMap初始化容量設(shè)置多少合適

那么,既然建議我們集合初始化的時候,要指定初始值大小,那么我們創(chuàng)建HashMap的時候,到底指定多少合適呢?

有些人會自然想到,我準備塞多少個元素我就設(shè)置成多少唄。比如我準備塞7個元素,那就new HashMap(7)。

但是,這么做不僅不對,而且以上方式創(chuàng)建出來的Map的容量也不是7。

因為,當我們使用HashMap(int initialCapacity)來初始化容量的時候,HashMap并不會使用我們傳進來的initialCapacity直接作為初始容量。

JDK會默認幫我們計算一個相對合理的值當做初始容量。所謂合理值,其實是找到第一個比用戶傳入的值大的2的冪。

也就是說,當我們new HashMap(7)創(chuàng)建HashMap的時候,JDK會通過計算,幫我們創(chuàng)建一個容量為8的Map;當我們new HashMap(9)創(chuàng)建HashMap的時候,JDK會通過計算,幫我們創(chuàng)建一個容量為16的Map。

但是,這個值看似合理,實際上并不盡然。因為HashMap在根據(jù)用戶傳入的capacity計算得到的默認容量,并沒有考慮到loadFactor這個因素,只是簡單機械的計算出第一個大約這個數(shù)字的2的冪。

loadFactor是負載因子,當HashMap中的元素個數(shù)(size)超過 threshold = loadFactor * capacity時,就會進行擴容。

也就是說,如果我們設(shè)置的默認值是7,經(jīng)過JDK處理之后,HashMap的容量會被設(shè)置成8,但是,這個HashMap在元素個數(shù)達到 8*0.75 = 6的時候就會進行一次擴容,這明顯是我們不希望見到的。

那么,到底設(shè)置成什么值比較合理呢?

這里我們可以參考JDK8中putAll方法中的實現(xiàn)的,這個實現(xiàn)在guava(21.0版本)也被采用。

這個值的計算方法就是:

return?(int)?((float)?expectedSize?/?0.75F?+?1.0F);

比如我們計劃向HashMap中放入7個元素的時候,我們通過expectedSize / 0.75F + 1.0F計算,7/0.75 + 1 = 10 ,10經(jīng)過JDK處理之后,會被設(shè)置成16,這就大大的減少了擴容的幾率。

當HashMap內(nèi)部維護的哈希表的容量達到75%時(默認情況下),會觸發(fā)rehash,而rehash的過程是比較耗費時間的。所以初始化容量要設(shè)置成expectedSize/0.75 + 1的話,可以有效的減少沖突也可以減小誤差。(大家結(jié)合這個公式,好好理解下這句話)

所以,我們可以認為,當我們明確知道HashMap中元素的個數(shù)的時候,把默認容量設(shè)置成expectedSize / 0.75F + 1.0F 是一個在性能上相對好的選擇,但是,同時也會犧牲些內(nèi)存。

這個算法在guava中有實現(xiàn),開發(fā)的時候,可以直接通過Maps類創(chuàng)建一個HashMap:

Map<String,?String>?map?=?Maps.newHashMapWithExpectedSize(7);

其代碼實現(xiàn)如下:

public?static?<K,?V>?HashMap<K,?V>?newHashMapWithExpectedSize(int?expectedSize)?{return?new?HashMap(capacity(expectedSize));}static?int?capacity(int?expectedSize)?{if?(expectedSize?<?3)?{CollectPreconditions.checkNonnegative(expectedSize,?"expectedSize");return?expectedSize?+?1;}?else?{return?expectedSize?<?1073741824???(int)((float)expectedSize?/?0.75F?+?1.0F)?:?2147483647;}}

但是,以上的操作是一種用內(nèi)存換性能的做法,真正使用的時候,要考慮到內(nèi)存的影響。但是,大多數(shù)情況下,我們還是認為內(nèi)存是一種比較富裕的資源。

但是話又說回來了,有些時候,我們到底要不要設(shè)置HashMap的初識值,這個值又設(shè)置成多少,真的有那么大影響嗎?其實也不見得!

可是,大的性能優(yōu)化,不就是一個一個的優(yōu)化細節(jié)堆疊出來的嗎?

再不濟,以后你寫代碼的時候,使用Maps.newHashMapWithExpectedSize(7);的寫法,也可以讓同事和老板眼前一亮。

或者哪一天你碰到一個面試官問你一些細節(jié)的時候,你也能有個印象,或者某一天你也可以拿這個出去面試問其他人~!啊哈哈哈。

【END】

近期熱文

?
  • 《 面試又翻車了》這次竟然和 Random 有關(guān)?

  • 因為我說:volatile 是輕量級的 synchronized,面試官讓我回去等通知!

  • 有人說:輕量級鎖一定比重量級鎖快!我忍不住笑了

關(guān)注下方二維碼,訂閱更多精彩內(nèi)容

朕已閱?

總結(jié)

以上是生活随笔為你收集整理的阿里巴巴Java开发手册建议设置HashMap的初始容量,但设置多少合适呢?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。