還在使用集合類完成這些功能?不妨來看看 Guava 集合類!!!
- 2020 年 3 月 13 日
- 筆記
日常開發中,小黑哥經常需要用到 Java 提供集合類完成各種需求。Java 集合類雖然非常強大實用,但是提供功能還是有點薄弱。
舉個例子,小黑哥最近接到一個需求,從輸入一個文檔中,統計一個關鍵詞出現的次數。程式碼如下:
雖然這個需求使用 Map
可以輕鬆搞定,但是小黑哥還是覺得這種寫法有點笨拙,如果沒有判空,將會導致 NPE 異常。
如果很多地方需要功能,我們就可以抽象出來,將其封裝成工具類。
不過上面的功能大家就不需要自己封裝,一款來自 Google 開源工具類-Guava,可以輕鬆的解決上面的統計問題。
Guava 介紹
Guava 是一款 Google 開源工具類,包含許多 Google 內部 Java
項目依賴的核心類。Guava 擴展 Java 基礎類工程,比如集合,並發等,也增加一些其他強大功能,比如快取,限流等功能。
另外 Guava 推出一些類,如 Optional
,甚至被 Java 開發者學習,後續增加到 JDK 中。
目前 Guava Github 倉庫已有 36k star,可以見到 Guava 受歡迎程度。
Guava 核心功能包括多個模組,今天小黑哥主要帶大家玩轉 Guava 集合類。
擴展集合類
Guava 創造很多 JDK 沒有,但是我們日常卻明顯有用的新集合類型。這些新類型使用 JDK 集合介面規範,所以使用方法與 JDK 集合框架差不多,並沒有增加很多使用難度。
Multiset
小黑哥第一次見到 Multiset
這個類,還以為是 Set
介面子類。實際上此『Set』,僅僅只是數學上集合概念。
Multiset
繼承 JDK Collection
介面,我們可以多次增加相同的元素,另外 Multiset
最大特定將會為元素計數,我們可以將它類似等同為 Map<E, Integer>
。
使用 Multiset
可以輕鬆解決開頭的問題。
使用 Multiset
簡化了程式碼,並且再也不用擔心新 NPE 的問題。
跟 JDK 集合類一樣,Multiset
也有許多子類。
這裡小黑哥提醒一下大家,雖然上面說過我們可以將 Multiset<E>
看做 Map<E, Integer>
,但是 Multiset
可不是 Map
的子類,它可是 血統純正的 Collection
子類。
Multimap
小黑哥有時會在業務需求中使用 Map<String,List<Integer>
實現下面的需求。
a->[1,2,3] b->4,c->[6,5]
使用 Map
+ List
這種結構比較笨拙,並且程式碼實現也比較繁瑣。Multimap
正式 Guava 中解決這種問題的新出的一個雷。
使用 Multimap
實現程式碼如下:
這裡小黑哥使用 Multimap
子類 HashMultimap
,其行為類似為 Map<K,Set<V>>
,也就是說 Value
對應的集合內部元素不能重複。如果需要保存的重複的元素我們可以使用 ArrayListMultimap
。
Multimap
還有其他子類,如圖所示:
BiMap
BiMap
可以用來實現鍵值對的雙向映射需求,這樣我們就可以通過 Key
查找對對應的 Value
,也可以使用 Value
查找對應的 Key
。
這個需求如果使用 Map
實現,我們就不得不使用兩個 Map
,維護雙向關係,並且任何改動還要保持同步。
使用 BiMap
修改上面的程式碼:
這裡需要注意,BiMap#put
方法不能加入重複元素, 若加入,將會拋錯。如果若特定值一定要替換,可以使用 BiMap#forcePut
代替。
敲黑板,這個知識點記下來。小黑哥使用過程中,就踩過這個坑。
同樣的 BiMap
也有各種實現類:
其他擴展集合類
Guava 另外還提供其他集合類,不過這些類使用起來有點複雜,小黑哥還未在業務程式碼中使用過,這裡簡單提下,感興趣同學可以深入了解一下。
- Table
- ClassToInstanceMap
- RangeSet
- RangeMap
集合工具類
除了上面提到的新集合類以外,Guava 提供通用的工具類:
這些工具類需對使用的方法,我們可以快速創建集合,分割集合,轉化集合等。
快速創建集合實例
使用工具類,我們可以快速創建集合。例如:
List<String> list=Lists.newArrayList(); Set<String> set=Sets.newHashSet(); Map<String,String> map=Maps.newHashMap();
相比於 new
集合方法,Guava 方法創建方式更加簡單。
List<String> list=new ArrayList<String>(); Set<String> set=new HashSet<String>(); Map<String,String> map=new HashMap<String, String>();
Guava 工具類智慧推導 List
泛型,再也不用兩側都重複寫泛型了。
另外還可以指定集合類的初始化大小。
Lists.transform
Lists#transform
方法可以替代繁瑣 for
循環,將元素轉化,創建一個新集合類。
不過使用這個方法我們要注意一點。
Lists#transform
內部使用懶載入的機制,只有在調用獲取的元素的時候,如 result.get
才會真正使用 Function
從源 List
獲取元素,做相應的轉化。每次獲取元素都將會使用 function
進行轉化。
所以使用 Lists#transform
得到 List
僅僅只是源 List
一個視圖,任何對源 List
的元素修改,都將會被反應到創建之後的 List
。任何對創建之後 List 中的元素進行修改,都不會生效。下次再次讀取元素時,將會發現相應修改的丟失了。。。
小黑哥之前就踩過這個坑,如果你有這種需求,可以使用以下方式創建一個新集合:
JDK8 之前版本,小黑哥經常使用該方法轉化
List
中的元素。不過你如果使用 JDK8,小黑哥還是推薦使用 Stream 流式編程。
交集並集差集
Sets
提供幾個方法,可以快速求出兩個 Set
集合的交集,並集以及差集。
不可變集合
不可變(Immutable)集合,顧名思義集合不可以被修改。初始創建不可變集合時嗎,需要傳入數據源,創建完成之後,集合就再也不能修改,增加,刪除元素,否則將會報錯。
這是一種防禦性策略,防止集合在後續操作中被修改,從而引發問題。
不可變集合優點在於:
- 由於不可變集合僅僅只能讀,多執行緒並發天然安全
- 由於不可變集合固定不變,可以將其當做常量安全,不用單線其他人修改
- 不可變集合佔用更少記憶體空間
- 不可變集合不可以被修改,所以不用擔心其他程式任意修改集合
Guava 不可變集合支援 JDK 所有集合介面:
我們可以使用如下幾種方式創建不可變集合,以 ImmutableList
為例:
List<String> fromList=Lists.newArrayList("點贊","關注"); // 從一個集合拷貝元素 ImmutableList.copyOf(fromList); ImmutableList.of("關注","Java極客技術"); ImmutableList.builder().add("關注").addAll(fromList).build();
總結
這篇文章小黑哥帶大家學習開源工具 Guava 集合的相關類使用方法,日常開發中我們善於使用這些工具類,不要自己重複造輪子。
本篇文章僅僅只是介紹 Guava 一小部分功能,還有很對功能,小黑哥也覺得很好用在。這裡推薦大家去查看 Guava 官方 wiki,查看具體使用方法。
如果大家還想知道其他開源工具類,給小黑哥點個贊,下次給大家帶來十分好用開源工具類~
歡迎關注我的公眾號:程式通事,獲得日常乾貨推送。如果您對我的專題內容感興趣,也可以關注我的部落格:studyidea.cn