Guava介紹之集合(Collection)相關的API
作者:Jack47
轉載請保留作者和原文出處
歡迎關注我的微信公眾賬號程序員杰克,兩邊的文章會同步,也可以添加我的RSS訂閱源。
本文是我寫的 Google開源的Java編程庫Guava系列 之一,主要介紹Guava中提供的集合(Collection)相關的API。
1. 一些小功能
集合聲明更簡單
Java中同質的范型集合是一個很大的特色,但是有些時候他們的構造函數有點太啰嗦了,比如:
Map<String, Map<String, Integer>> lookup = new HashMap<String, Map<String, Integer>>();
在Java 7中通過鉆石操作符 <> 來允許有限的非正式的類型推導。上面的例子可以這樣寫:
Map<String, Map<String, Integer>> lookup = new HashMap<>();
Guava提供了一些使用范型來進行右側類型推導的靜態函數,使得集合的聲明更簡單,上面的例子可以這么寫:
Map<String, Map<String, String>> map = Maps.newHashMap(); List<List<Map<String, String>>> list = Lists.newArrayList();
集合初始化更簡單
可以在集合聲明時進行初始化
Set<String> set = Sets.newHashSet("one", "two", "three"); Map<String, String> map = ImmutableMap.of("ON", true, "OFF", false);
2. 不可變性(Immutability)
大部分google提供的集合都提供不可變的版本。當你不會修改一個集合,或者期望一個集合是固定不變的,那么一個很好的習慣是防御式地把它拷貝成一個不可變的集合。
注意
Guava中提供的不可變集合的實現是不允許有空值`null`的。因為通過研究Google內部代碼庫發現在集合中,只有5%的情況下是允許有空值的,剩下的95%情況下最好是遇到空值就快速失敗(failing fast)。如果需要空值,可以使用JDK中提供的 Collections.unmodifiableList 這類允許空值的集合實現。
更多關于使用或者避免使用 null 的細節見 Using And Avoiding Null Explained
不可變的好處:
- 可以放心的給不信任的庫使用
- 線程安全:可以被多個線程使用而不會有競爭條件發生
- 不需要同步(synchronization)的邏輯,不需要支持互斥
- 設計和實現很簡單。所有不可變的集合實現比可變版本的內存效率要高,分析見 這里
如何使用
有多種方法來得到一個不可變的集合:
-
使用 of 函數
ImmutableSet<Integer> numbers = ImmutableSet.of(10, 30, 40, 50); -
使用 copyOf 函數
ImmutableSet<Integer> another = ImmutableSet.copyOf(numberSet);
所有不可變的集合都通過 asList() 提供了一個不可變的List(ImmutableList)視圖。例如數據存儲在一個 ImmutableSortedSet 里,可以通過 sortedSet.asList().get(k) 來獲得第 k 個最小的元素。
JDK雖然提供了 Collections.unmodifiableXXX 方法,但是有一些問題:
- 非常笨重,使用起來很啰嗦,用著不爽
- 不安全:只有當沒有對原始集合的引用時,這個函數返回的集合才是真的不可變的
- 不夠高效:數據結構里還是有可變集合里關于并發修改的檢查,存儲哈希表的額外空間等。
3. 新的集合類型
Guava引入的新的集合類型并沒有暴露原始的構造函數,或者提供方便初始化操作的工具類,而是直接使用靜態工廠函數,例如:
MultiMap<String, Integer> multiMap = HashMultiMap.create();
MultiMap
容許一個key有多個值的 MultiMap, MultiMap<K, V> 可以取代傳統的 Map<K, Collection<V>> 。也可以使用值為鏈表的 ListMultiMap 或者集合 SetMultiMap 。
Multiset
Multiset支持添加多次相同的值,支持對值進行計數。
Multiset<Integer> multiSet = HashMultiset.create(); multiSet.add(10); multiSet.add(30); multiSet.add(30); multiSet.add(40); multiSet.count(30); // 2 multiSet.size(); // 4
Table
表結構的數據類型 Table ,它像Map一樣,但是支持兩種鍵--行鍵(row key)和列鍵(column key)。
4. 謂語(Predicate)和過濾器(Filter)
謂語(Predicate)是一個只包含一個返回布爾類型的函數的簡單接口。它的作用是給定一個輸入,判斷是否滿足條件。它可以用來過濾集合,例如實現一個過濾出老客戶的 Predicate 。
static class LoyalCustomer implements Predicate<Customer> { public boolean apply(Customer customer) { return CustomerType.LOYAL == customer.getCustomerType(); } } Collection<Customer> loyalCustomers = Collections2.filter(customers, new LoyalCustomer());
filter函數的語法是:
Collection<E> filter(Collection<E> unfiltered, Predicate<E> predicate)內置的Predicate
Predicates 類包含了 and , or , not in 這幾個靜態函數來方便構建復雜的謂語。
Predicate<String> commonList = and(in(list1), in(list2, or(in(list3));
Predicates 類也包含了很多非常方便的函數,例如 notNull , instanceOf , contains 等。
SortedMaps.filterValues(map, Predicates.notNull());
如果看到這里還意猶未盡的話,建議去看看 源代碼 和 單測的代碼 ,里面有詳盡的用法!
參考資料:
如果您看了本篇博客,覺得對您有所收獲,請點擊右下角的“推薦”,讓更多人看到!
資助Jack47寫作,打賞一個雞蛋灌餅錢吧
微信打賞
支付寶打賞