理解不可變集合 | Guava Immutable與JDK unmodifiableList

1伴奥、為什么需要不可變集合

  • (1)保證線程安全:在并發(fā)程序中乍恐,使用Immutable既保證線程安全性默蚌,也大大增強了并發(fā)時的效率(跟并發(fā)鎖方式相比)。尤其當(dāng)一個對象是值對象時漱办,更應(yīng)該考慮采用Immutable方式这刷;
  • (2)被不可信的類庫使用時會很安全;
  • (3)如果一個對象不需要支持修改操作(mutation)娩井,將會節(jié)省空間和時間的開銷暇屋;經(jīng)過分析,所有不可變的集合實現(xiàn)都比可變集合更加有效地利用內(nèi)存撞牢;
  • (4)可以當(dāng)作一個常量來對待率碾,并且這個對象在以后也不會被改變叔营。

將一個對象復(fù)制一份成immutable的屋彪,是一個防御性編程技術(shù)所宰。

2、JDK中提供的不可變集合:真的做到了不可變畜挥?

在JDK類庫中很多集合(List仔粥、Set、Map等)都可以調(diào)用Collections類提供的靜態(tài)方法unmodifiableXXX(…)來得到一個不可修改的視圖蟹但,例如:

// 下面的代碼利用Collections.unmodifiableList(list)得到一個不可修改的集合unmodifiableList
List list = new ArrayList();
list.add("wyp");
list.add("good");

List unmodifiableList = Collections.unmodifiableList(list);
System.out.println(unmodifiableList);//[wyp, good]
unmodifiableList.add("add");

當(dāng)unmodifiableList.add(“add”)時躯泰,運行代碼將會出現(xiàn)以下異常:

Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableCollection.add(Collections.java:1018)
at com.wyp.test.testFiles(test.java:152)
at com.wyp.test.main(test.java:160)

說明如果直接add是不可以的,符合不可變的定義华糖。
一切看起來很不錯麦向,因為調(diào)用unmodifiableList.add()會拋出一個java.lang.UnsupportedOperationException。但如果有用戶修改了list客叉,會發(fā)生什么情況诵竭?在上述代碼的下面加入以下代碼:

list.add("add");
System.out.println(unmodifiableList);

當(dāng)你再次打印unmodifiableList的時候,你會發(fā)現(xiàn)結(jié)果是[wyp, good, add]兼搏,多了一個"add"元素卵慰。unmodifiableList不是不可變的嗎?這顯然不是我們期望的佛呻。

說明:Collections.unmodifiableList(…)實現(xiàn)的不是真正的不可變集合裳朋,當(dāng)原始集合被修改后,不可變集合里面的元素也是跟著發(fā)生變化吓著。

利用JDK類庫中提供的unmodifiableXXX方法最少存在以下幾點不足:
  • 笨拙:因為你每次都得寫那么多代碼鲤嫡;
  • 不安全:如果沒有引用到原來的集合,這種情況之下才會返回唯一真正永恒不變的集合绑莺;
  • 效率很低:返回的不可修改的集合數(shù)據(jù)結(jié)構(gòu)仍然具有可變集合的所有開銷泛范。

3、Guava提供的Immutable:真正的不可變集合

Guava類庫中提供的Immutable才是真正的不可修改的集合紊撕。

import com.google.common.collect.ImmutableList;
ImmutableList immutableList = ImmutableList.of("wyp", "good");
  • 當(dāng)你往immutableList 中添加元素罢荡,也會拋出java.lang.UnsupportedOperationException異常;

  • 修改原集合后对扶,immutable集合不變:
    public void testImmutable(){
    ArrayList<String> stringArrayList = Lists.newArrayList("wo","bu","ke","bian");
    ImmutableList<String> immutableList = ImmutableList.copyOf(stringArrayList);
    // 嘗試add: java.lang.UnsupportedOperationException
    // immutableList.add("!!!");

        // 嘗試修改原集合:immutableList不變区赵,還是 [wo, bu, ke, bian]
        stringArrayList.add("!!!");
        System.out.println(immutableList);
      }
    
閱讀源碼:Guava Immutable的實現(xiàn)原理

單步調(diào)試走起:

1:調(diào)用copyOf方法

2:對傳入的集合做類型判斷

如果傳入的結(jié)合本身就是一個不可變集合,那么asList獲取視圖后返回浪南;如果不是笼才,則執(zhí)行construct方法;


3:再調(diào)用asImmutableList方法络凿,依舊把原集合傳進去

4:asImmutableList方法

上一步的checkNotNull方法將原集合轉(zhuǎn)換成了對象數(shù)組傳開了進來骡送,同時傳入了這個數(shù)組的長度昂羡,這里用case對長度做了判斷,以分別處理:

  • case 0:長度是0摔踱,那么of應(yīng)該是返回一個空的不可變集合虐先,而一般來說這個空的不可變集合是可以復(fù)用的;

  • case 1:長度是1派敷,那么直接用這個元素new一個對象實例蛹批;

  • default:這里有個地方?jīng)]看懂

     if (length < elements.length) {
           elements = arraysCopyOf(elements, length);
     }
    

這里是由上一步而來的:

asImmutableList(Object[] elements) --> ImmutableList<E> asImmutableList(Object[] elements, int length)

所以這里的length就是elements的length,那么這個if又有何意義篮愉?不明白...反正是直接執(zhí)行

return new RegularImmutableList<E>(elements);

了腐芍,接著往下看:

RegularImmutableList

這是一個內(nèi)部類,直借截取了一部分试躏,里面有一個copyIntoArray方法

copyIntoArray

經(jīng)過一系列調(diào)用猪勇,得到了一個array

最后一步一步返回。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末颠蕴,一起剝皮案震驚了整個濱河市泣刹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌裁替,老刑警劉巖项玛,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異弱判,居然都是意外死亡襟沮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門昌腰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來开伏,“玉大人,你說我怎么就攤上這事遭商」塘椋” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵劫流,是天一觀的道長巫玻。 經(jīng)常有香客問我,道長祠汇,這世上最難降的妖魔是什么仍秤? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮可很,結(jié)果婚禮上诗力,老公的妹妹穿的比我還像新娘。我一直安慰自己我抠,他們只是感情好苇本,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布袜茧。 她就那樣靜靜地躺著,像睡著了一般瓣窄。 火紅的嫁衣襯著肌膚如雪笛厦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天康栈,我揣著相機與錄音递递,去河邊找鬼喷橙。 笑死啥么,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的贰逾。 我是一名探鬼主播悬荣,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼疙剑!你這毒婦竟也來了氯迂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤言缤,失蹤者是張志新(化名)和其女友劉穎嚼蚀,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體管挟,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡轿曙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了僻孝。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片导帝。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖穿铆,靈堂內(nèi)的尸體忽然破棺而出您单,到底是詐尸還是另有隱情,我是刑警寧澤荞雏,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布虐秦,位于F島的核電站,受9級特大地震影響凤优,放射性物質(zhì)發(fā)生泄漏悦陋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一别洪、第九天 我趴在偏房一處隱蔽的房頂上張望叨恨。 院中可真熱鬧,春花似錦挖垛、人聲如沸痒钝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽送矩。三九已至蚕甥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間栋荸,已是汗流浹背菇怀。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留晌块,地道東北人爱沟。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像匆背,于是被迫代替她去往敵國和親呼伸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法钝尸,類相關(guān)的語法括享,內(nèi)部類的語法,繼承相關(guān)的語法珍促,異常的語法铃辖,線程的語...
    子非魚_t_閱讀 31,625評論 18 399
  • Overview 本節(jié)主要介紹幾種語言中的數(shù)組和集合的對應(yīng)用法。 數(shù)組在程序中一般用于表示一段連續(xù)的空間猪叙。通常來說...
    bookislife閱讀 952評論 0 0
  • 對象的創(chuàng)建與銷毀 Item 1: 使用static工廠方法娇斩,而不是構(gòu)造函數(shù)創(chuàng)建對象:僅僅是創(chuàng)建對象的方法,并非Fa...
    孫小磊閱讀 1,982評論 0 3
  • 《Kotlin 極簡教程 》第5章 集合類 《Kotlin極簡教程》正式上架: 點擊這里 > 去京東商城購買閱讀 ...
    光劍書架上的書閱讀 2,222評論 0 11
  • 參加讀書筆記的第二本書仍然是老板送的 沐悦,汗顏啊成洗,下次我要看自己挑選的,這書看名字就知道是工具書藏否,在兩周內(nèi)看完還是可...
    naiwohe閱讀 411評論 1 0