GUAVA--集合(不可變集合)

一、爲何要使用不可變集合

優勢:java

  1. 當對象被不可信的庫調用時,不可變形式是安全的;
  2. 不可變對象被多個線程調用時,不存在競態條件問題;
  3. 不可變集合不須要考慮變化,所以能夠節省時間和空間。全部不可變的集合都比它們的可變形式有更好的內存利用率;
  4. 不可變對象由於有固定不變,能夠做爲常量來安全使用。

建立對象的不可變拷貝是一項很好的防護性編程技巧。Guava 爲全部 JDK 標準集合類型和 Guava 新集合類型 都提供了簡單易用的不可變版本。編程

JDK 也提供了 Collections.unmodifiableXXX 方法把集合包裝爲不可變形式,但Guava認爲不夠好:安全

  • 笨重並且累贅:不能溫馨地用在全部想作防護性拷貝的場景;
  • 不安全:要保證沒人經過原集合的引用進行修改,返回的集合纔是事實上不可變的;
  • 低效:包裝過的集合仍然保有可變集合的開銷,好比並發修改的檢查、散列表的額外空間,等等。

若是你沒有修改某個集合的需求,或者但願某個集合保持不變時,把它防護性地拷貝到不可變集合是個很好的實 踐。數據結構

重要提示:全部 Guava 不可變集合的實現都不接受 null 值。咱們對 Google 內部的代碼庫作過詳細研究,發現 只有 5%的狀況須要在集合中容許 null 元素,剩下的 95%場景都是遇到 null 值就快速失敗。若是你須要在不可 變集合中使用 null,請使用 JDK 中的 Collections.unmodifiableXXX 方法。更多細節建議請參考「使用和避免 null」。併發

二、怎麼使用不可變集合

2.一、建立不可變集合

// copyOf 方法,如 ImmutableSet.copyOf(set);
List<String> list = Arrays.asList("a", "b", "c");
ImmutableSet<String> strings = ImmutableSet.copyOf(list);

// of 方法,如 ImmutableSet.of(「a」, 「b」, 「c」)或 ImmutableMap.of(「a」, 1, 「b」, 2);
ImmutableSet<String> of = ImmutableSet.of("a", "b", "c", "d", "e");

// Builder 工具
ImmutableSet<String> set = ImmutableSet.<String>builder()
	.add("a")
	.add("b")
	.add("c")
.build();

另外,對有序不可變集合來講,排序是在構造集合的時候完成的,如:工具

ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");

會在構造時就把元素排序爲 a, b, c, d。性能

2.二、更智能的 copyOf

ImmutableXXX.copyOf 方法會嘗試在安全的時候避免作拷貝——實際的實現細節不詳,但一般來講是 很智能的,好比:ui

ImmutableSet<String> foobar = ImmutableSet.of("foo", "bar", "baz");
	thingamajig(foobar);
	void thingamajig(Collection<String> collection) {
	ImmutableList<String> defensiveCopy = ImmutableList.copyOf(collection);
	...
}

在這段代碼中,ImmutableList.copyOf(foobar)會智能地直接返回 foobar.asList(),它是一個 ImmutableSet 的常量時間複雜度的 List 視圖。google

做爲一種探索,ImmutableXXX.copyOf(ImmutableCollection)會試圖對以下狀況避免線性時間拷貝:線程

  • 在常量時間內使用底層數據結構是可能的——例如,ImmutableSet.copyOf(ImmutableList)就不能在常量時間內完成。
  • 不會形成內存泄露——例如,你有個很大的不可變集合 ImmutableList hugeList, ImmutableList.copyOf(hugeList.subList(0, 10))就會顯式地拷貝,以避免沒必要要地持有 hugeList 的引用。
  • 不改變語義——因此 ImmutableSet.copyOf(myImmutableSortedSet)會顯式地拷貝,由於和基於比較器的 ImmutableSortedSet 相比,ImmutableSet對hashCode()和 equals 有不一樣語義。

在可能的狀況下避免線性拷貝,能夠最大限度地減小防護性編程風格所帶來的性能開銷。

2.三、asList視圖

全部不可變集合都有一個 asList()方法提供 ImmutableList 視圖,來幫助你用列表形式方便地讀取集合元素。例 如,你可使用 sortedSet.asList().get(k)從 ImmutableSortedSet 中讀取第 k 個最小元素。

asList()返回的 ImmutableList 一般是——並不老是——開銷穩定的視圖實現,而不是簡單地把元素拷貝進 Lis t。也就是說,asList 返回的列表視圖一般比通常的列表平均性能更好,好比,在底層集合支持的狀況下,它老是 使用高效的 contains 方法。

2.四、關聯可變集合和不可變集合

可變集合接口 屬於JDK仍是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

三、例子

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Lists;

public class Guava {
	public static void main(String[] args) {
	//建立 3鍾方式
        //一、of方法
        ImmutableList<String> immutableList = ImmutableList.of("1", "3", "2");
        System.out.println(immutableList);
        //二、copyOf方法
        ImmutableList<Object> immutableList1 = ImmutableList.copyOf(Lists.newArrayList(1, "abc", 3d));
        System.out.println(immutableList1);
        //三、builder構建
        ImmutableList<Integer> immutableList2 = ImmutableList.<Integer>builder().add(3).add(5).add(7).build();
        System.out.println(immutableList2);

        ImmutableSet<String> immutableSet = ImmutableSet.of("beibei", "jingjing", "huanhuan");
        System.out.println(immutableSet);
        //不可變集合均可以使用asList方法返回一個ImmutableList視圖
        ImmutableList<String> immutableSetToList = immutableSet.asList();
        System.out.println(immutableSetToList);

        //會自動排序
        ImmutableSortedSet<String> immutableSortedSet = ImmutableSortedSet.of("1", "32", "3");
        System.out.println(immutableSortedSet);

        ImmutableMap<String, Integer> immutableMap = ImmutableMap.of("1", 11, "2", 22);
        System.out.println(immutableMap);
        System.out.println(immutableMap.asMultimap());
	}
}
輸出結果:
[1, 3, 2]
[1, abc, 3.0]
[3, 5, 7]
[beibei, jingjing, huanhuan]
[beibei, jingjing, huanhuan]
[1, 3, 32]
{1=11, 2=22}
{1=[11], 2=[22]}

四、小結

Guava建立不可變集合的這些方法裏,ImmutableList、ImmutableSet、ImmutableSortedSet都是繼承了全部集合的父類Collection,建立出來的集合可使用JDK相對應集合的方法,是能夠直接賦給JDK相對應集合的。其中ImmutableMap是實現Map接口的。

ImmutableList<String> immutableList = ImmutableList.of("1", "3", "2");
List<String> list = new ArrayList<String>();
list = immutableList;
immutableList.get(0);
相關文章
相關標籤/搜索