Guava學習筆記:Immutable(不可變)集合
不可變集合,顧名思義就是說集合是不可被修改的。集合的資料項是在建立的時候提供,並且在整個生命週期中都不可改變。
為什麼要用immutable物件?immutable物件有以下的優點:
1.對不可靠的客戶程式碼庫來說,它使用安全,可以在未受信任的類庫中安全的使用這些物件
2.執行緒安全的:immutable物件在多執行緒下安全,沒有競態條件
3.不需要支援可變性, 可以儘量節省空間和時間的開銷. 所有的不可變集合實現都比可變集合更加有效的利用記憶體 (analysis)
4.可以被使用為一個常量,並且期望在未來也是保持不變的
immutable物件可以很自然地用作常量,因為它們天生就是不可變的對於immutable物件的運用來說,它是一個很好的防禦程式設計(defensive programming)的技術實踐。
JDK中實現immutable集合
在JDK中提供了Collections.unmodifiableXXX系列方法來實現不可變集合, 但是存在一些問題,下面我們先看一個具體例項:
import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.junit.Test; public class ImmutableTest { @Test public void testJDKImmutable(){ List<String> list=new ArrayList<String>(); list.add("a"); list.add("b"); list.add("c"); System.out.println(list); List<String> unmodifiableList=Collections.unmodifiableList(list); System.out.println(unmodifiableList); List<String> unmodifiableList1=Collections.unmodifiableList(Arrays.asList("a","b","c")); System.out.println(unmodifiableList1); String temp=unmodifiableList.get(1); System.out.println("unmodifiableList [0]:"+temp); list.add("baby"); System.out.println("list add a item after list:"+list); System.out.println("list add a item after unmodifiableList:"+unmodifiableList); unmodifiableList1.add("bb"); System.out.println("unmodifiableList add a item after list:"+unmodifiableList1); unmodifiableList.add("cc"); System.out.println("unmodifiableList add a item after list:"+unmodifiableList); } }
輸出:
[a, b, c] [a, b, c] [a, b, c] unmodifiableList [0]:b list add a item after list:[a, b, c, baby] list add a item after unmodifiableList1:[a, b, c, baby]
說明:Collections.unmodifiableList實現的不是真正的不可變集合,當原始集合修改後,不可變集合也發生變化。不可變集合不可以修改集合資料,當強制修改時會報錯,例項中的最後兩個add會直接丟擲不可修改的錯誤。
總結一下JDK的Collections.unmodifiableXXX方法實現不可變集合的一些問題:
1.它用起來笨拙繁瑣你不得不在每個防禦性程式設計拷貝的地方用這個方法
2.它不安全:如果有物件reference原始的被封裝的集合類,這些方法返回的集合也就不是正真的不可改變。
3.效率低:因為它返回的資料結構本質仍舊是原來的集合類,所以它的操作開銷,包括併發下修改檢查,hash table裡的額外資料空間都和原來的集合是一樣的。
Guava的immutable集合
Guava提供了對JDK裡標準集合類裡的immutable版本的簡單方便的實現,以及Guava自己的一些專門集合類的immutable實現。當你不希望修改一個集合類,或者想做一個常量集合類的時候,使用immutable集合類就是一個最佳的程式設計實踐。
注意:每個Guava immutable集合類的實現都拒絕null值。我們做過對Google內部程式碼的全面的調查,並且發現只有5%的情況下集合類允許null值,而95%的情況下都拒絕null值。萬一你真的需要能接受null值的集合類,你可以考慮用Collections.unmodifiableXXX。
Immutable集合使用方法:
一個immutable集合可以有以下幾種方式來建立:
1.用copyOf方法, 譬如, ImmutableSet.copyOf(set)
2.使用of方法,譬如,ImmutableSet.of("a", "b", "c")或者ImmutableMap.of("a", 1, "b", 2)
3.使用Builder類
例項:
@Test public void testGuavaImmutable(){ List<String> list=new ArrayList<String>(); list.add("a"); list.add("b"); list.add("c"); System.out.println("list:"+list); ImmutableList<String> imlist=ImmutableList.copyOf(list); System.out.println("imlist:"+imlist); ImmutableList<String> imOflist=ImmutableList.of("peida","jerry","harry"); System.out.println("imOflist:"+imOflist); ImmutableSortedSet<String> imSortList=ImmutableSortedSet.of("a", "b", "c", "a", "d", "b"); System.out.println("imSortList:"+imSortList); list.add("baby"); System.out.println("list add a item after list:"+list); System.out.println("list add a item after imlist:"+imlist); ImmutableSet<Color> imColorSet = ImmutableSet.<Color>builder() .add(new Color(0, 255, 255)) .add(new Color(0, 191, 255)) .build(); System.out.println("imColorSet:"+imColorSet); }
輸出:
list:[a, b, c]
imlist:[a, b, c]
imOflist:[peida, jerry, harry]
imSortList:[a, b, c, d]
list add a item after list:[a, b, c, baby]
list add a item after imlist:[a, b, c]
imColorSet:[java.awt.Color[r=0,g=255,b=255], java.awt.Color[r=0,g=191,b=255]]
對於排序的集合來說有例外,因為元素的順序在構建集合的時候就被固定下來了。譬如,ImmutableSet.of("a", "b", "c", "a", "d", "b"),對於這個集合的遍歷順序來說就是"a", "b", "c", "d"。
更智慧的copyOf
copyOf方法比你想象的要智慧,ImmutableXXX.copyOf會在合適的情況下避免拷貝元素的操作-先忽略具體的細節,但是它的實現一般都是很“智慧”的。譬如:
@Test public void testCotyOf(){ ImmutableSet<String> imSet=ImmutableSet.of("peida","jerry","harry","lisa"); System.out.println("imSet:"+imSet); ImmutableList<String> imlist=ImmutableList.copyOf(imSet); System.out.println("imlist:"+imlist); ImmutableSortedSet<String> imSortSet=ImmutableSortedSet.copyOf(imSet); System.out.println("imSortSet:"+imSortSet); List<String> list=new ArrayList<String>(); for(int i=0;i<20;i++){ list.add(i+"x"); } System.out.println("list:"+list); ImmutableList<String> imInfolist=ImmutableList.copyOf(list.subList(2, 18)); System.out.println("imInfolist:"+imInfolist); int imInfolistSize=imInfolist.size(); System.out.println("imInfolistSize:"+imInfolistSize); ImmutableSet<String> imInfoSet=ImmutableSet.copyOf(imInfolist.subList(2, imInfolistSize-3)); System.out.println("imInfoSet:"+imInfoSet); }
輸出:
imSet:[peida, jerry, harry, lisa] imlist:[peida, jerry, harry, lisa] imSortSet:[harry, jerry, lisa, peida] list:[0x, 1x, 2x, 3x, 4x, 5x, 6x, 7x, 8x, 9x, 10x, 11x, 12x, 13x, 14x, 15x, 16x, 17x, 18x, 19x] imInfolist:[2x, 3x, 4x, 5x, 6x, 7x, 8x, 9x, 10x, 11x, 12x, 13x, 14x, 15x, 16x, 17x] imInfolistSize:16 imInfoSet:[4x, 5x, 6x, 7x, 8x, 9x, 10x, 11x, 12x, 13x, 14x]
在這段程式碼中,ImmutableList.copyOf(imSet)會智慧地返回時間複雜度為常數的ImmutableSet的imSet.asList()。
一般來說,ImmutableXXX.copyOf(ImmutableCollection)會避免線性複雜度的拷貝操作。如在以下情況:
這個操作有可能就利用了被封裝資料結構的常數複雜度的操作。但例如ImmutableSet.copyOf(list)不能在常數複雜度下實現。
這樣不會導致記憶體洩漏-例如,你有個ImmutableList<String> imInfolist,然後你顯式操作ImmutableList.copyOf(imInfolist.subList(0, 10))。這樣的操作可以避免意外持有不再需要的在hugeList裡元素的reference。
它不會改變集合的語意-像ImmutableSet.copyOf(myImmutableSortedSet)這樣的顯式拷貝操作,因為在ImmutableSet裡的hashCode()和equals()的含義和基於comparator的ImmutableSortedSet是不同的。
這些特性有助於最優化防禦性程式設計的效能開銷。
asList方法
所有的immutable集合都以asList()的形式提供了ImmutableList檢視(view)。譬如,你把資料放在ImmutableSortedSet,你就可以呼叫sortedSet.asList().get(k)來取得前k個元素的集合。
返回的ImmutableList常常是個常數複雜度的檢視,而不是一個真的拷貝。也就是說,這個返回集合比一般的List更智慧-譬如,它會更高效地實現contains這樣的方法。
例項:
@Test public void testAsList(){ ImmutableList<String> imList=ImmutableList.of("peida","jerry","harry","lisa","jerry"); System.out.println("imList:"+imList); ImmutableSortedSet<String> imSortList=ImmutableSortedSet.copyOf(imList); System.out.println("imSortList:"+imSortList); System.out.println("imSortList as list:"+imSortList.asList()); }
輸出:
imList:[peida, jerry, harry, lisa, jerry]
imSortList:[harry, jerry, lisa, peida]
imSortList as list:[harry, jerry, lisa, peida]
Guava集合和不可變對應關係
可變集合型別 | 可變集合源:JDK or Guava? | Guava不可變集合 |
Collection | JDK | ImmutableCollection |
List | JDK | ImmutableList |
Set | JDK | ImmutableSet |
SortedSet/NavigableSet | JDK | ImmutableSortedSet |
Map | JDK | ImmutableMap |
SortedMap | JDK | ImmutableSortedMap |
Multiset | Guava | ImmutableMultiset |
SortedMultiset | Guava | ImmutableSortedMultiset |
Multimap | Guava | ImmutableMultimap |
ListMultimap | Guava | ImmutableListMultimap |
SetMultimap | Guava | ImmutableSetMultimap |
BiMap | Guava | ImmutableBiMap |
ClassToInstanceMap | Guava | ImmutableClassToInstanceMap |
Table | Guava | ImmutableTable |
相關推薦
Guava學習筆記:Immutable(不可變)集合
不可變集合,顧名思義就是說集合是不可被修改的。集合的資料項是在建立的時候提供,並且在整個生命週期中都不可改變。 為什麼要用immutable物件?immutable物件有以下的優點: 1.對不可靠的客戶程式碼庫來說,它使用安全,可以在未受信任的類庫中安全的使用這些物件 2.執行緒安全
【java代碼之美】---guava之Immutable(不可變)集合
實例 bubuko mage string 工具類 clas tle wrapper 系列 Immutable(不可變)集合 一、概述 guava是google的一個庫,彌補了java語言的很多方面的不足,很多在java8中已有實現,暫時不展開。Col
Guava學習筆記:Guava新集合-Table等
Table 當我們需要多個索引的資料結構的時候,通常情況下,我們只能用這種醜陋的Map<FirstName, Map<LastName, Person>>來實現。為此Guava提供了一個新的集合型別-Table集合型別,來支援這種資料結構的使用場景。Table支援“row”和“
Guava學習筆記:Guava新增集合型別-Multiset
Guava引進了JDK裡沒有的,但是非常有用的一些新的集合型別。所有這些新集合型別都能和JDK裡的集合平滑整合。Guava集合非常精準地實現了JDK定義的介面。Guava中定義的新集合有: Multiset SortedMultiset Multimap ListMultimap SetMult
Guava學習筆記:Guava新增集合型別-Multimap
在日常的開發工作中,我們有的時候需要構造像Map<K, List<V>>或者Map<K, Set<V>>這樣比較複雜的集合型別的資料結構,以便做相應的業務邏輯處理。例如: import java.util.ArrayList; import java
Guava學習筆記:Guava新增集合型別-Bimap
BiMap提供了一種新的集合型別,它提供了key和value的雙向關聯的資料結構。 通常情況下,我們在使用Java的Map時,往往是通過key來查詢value的,但是如果出現下面一種場景的情況,我們就需要額外編寫一些程式碼了。首先來看下面一種表示標識序號和檔名的map結構。 @Test
Guava學習筆記:Optional優雅的使用null
asset 不包含 你在 rgs 命名 靜態 不清晰 ces throw 在我們學習和使用Guava的Optional之前,我們需要來了解一下Java中null。因為,只有我們深入的了解了null的相關知識,我們才能更加深入體會領悟到Guava的Optional設計和使用上
Guava學習筆記:Guava cache
快取,在我們日常開發中是必不可少的一種解決效能問題的方法。簡單的說,cache 就是為了提升系統性能而開闢的一塊記憶體空間。 快取的主要作用是暫時在記憶體中儲存業務系統的資料處理結果,並且等待下次訪問使用。在日常開發的很多場合,由於受限於硬碟IO的效能或者我們自
Guava學習筆記:Preconditions優雅的檢驗引數
在日常開發中,我們經常會對方法的輸入引數做一些資料格式上的驗證,以便保證方法能夠按照正常流程執行下去。對於可預知的一些資料上的錯誤,我們一定要做事前檢測和判斷,來避免程式流程出錯,而不是完全通過錯誤處理來保證流程正確執行,畢竟錯誤處理是比較消耗資源的方式。在平常情況下我們對引數的判斷都需要自己來逐個寫方法
Guava學習筆記:EventBus
EventBus是Guava的事件處理機制,是設計模式中的觀察者模式(生產/消費者程式設計模型)的優雅實現。對於事件監聽和釋出訂閱模式,EventBus是一個非常優雅和簡單解決方案,我們不用建立複雜的類和介面層次結構。 Observer模式是比較常用的設計模式之一,雖然有時候在具體程式碼裡,它不一定
Guava學習筆記:複寫的Object常用方法
在Java中Object類是所有類的父類,其中有幾個需要override的方法比如equals,hashCode和toString等方法。每次寫這幾個方法都要做很多重複性的判斷, 很多類庫提供了覆寫這幾個方法的工具類, Guava也提供了類似的方式。下面我們來看看Guava中這幾個方法簡單使用。 e
Guava學習筆記:簡化異常處理的Throwables類
有時候, 當我們我們捕獲異常, 並且像把這個異常傳遞到下一個try/catch塊中。Guava提供了一個異常處理工具類, 可以簡單地捕獲和重新丟擲多個異常。例如: import java.io.IOException; import org.junit.Test; import com.goog
Guava學習筆記:Range
在Guava中新增了一個新的型別Range,從名字就可以瞭解到,這個是和區間有關的資料結構。從Google官方文件可以得到定義:Range定義了連續跨度的範圍邊界,這個連續跨度是一個可以比較的型別(Comparable type)。比如1到100之間的整型資料。 在數學裡面的範圍是有邊界和無邊界之分
Guava學習筆記:Ordering犀利的比較器
Ordering是Guava類庫提供的一個犀利強大的比較器工具,Guava的Ordering和JDK Comparator相比功能更強。它非常容易擴充套件,可以輕鬆構造複雜的comparator,然後用在容器的比較、排序等操作中。 本質上來說,Ordering 例項無非就是一個特殊的Comparat
MySQL學習筆記:計算機服務中找不到MySQL服務
技術分享 sql AS 目錄 exe class sql安裝 .com com 不知道什麽原因,連接了遠程服務器之後,本地服務就連接不上。 經排查,發現服務中的MySQL服務居然不見,一番搜索之後,在CMD中進入到MySQL安裝目錄的bin下執行以下語句: mys
Guava學習筆記(二):基礎(Joiner,Objects,Splitter及Strings)
nonnull obj expect null dto 字符 情況 core cte 添加Maven依賴 JoinerTest import com.google.common.base.Joiner; import org.junit.Assert; import org
Java學習筆記:Map集合-HashMap和HashTable(01)
在面試的過程中經常會被問到一個問題,HashMap和HashTable有什麼不同?我就大概的整理了一些,與大家分享。 一、相同點 都實現了Map介面,底層都是採用的雜湊表(陣列 + 單向連結串列,在JDK1.8以後又加入了紅黑樹。即當連結串列長度大於8時,單向連結串列轉換成紅黑樹--提
[Google Guava] 2.1-不可變集合
原文連結 譯者:沈義揚 範例 public static final ImmutableSet<String> COLOR_NAMES = ImmutableSet.of( "red", "orange", "yellow",
敏捷開發學習筆記:需求優先順序方法(需求做還是不做)
轉自:https://mp.weixin.qq.com/s?__biz=MzIwMDMyNTE4Ng==&mid=401739882&idx=1&sn=531e9ea49456e55a8437cd8b995c5237&mpshare=1&
python學習筆記:集合set,函式基礎
1、遍歷字典 for k,v in d: 則k,v分別是字典中鍵值對的鍵和值 2、字典的推導式 比如d = {x:x**2 for x in range(10)} &nb