天天看點

Java-類庫-Guava-Immutable(不可變)集合

不可變集合,顧名思義就是說集合是不可被修改的。集合的資料項是在建立的時候提供,并且在整個生命周期中都不可改變。

  為什麼要用immutable對象?immutable對象有以下的優點:

    1.對不可靠的客戶代碼庫來說,它使用安全,可以在未受信任的類庫中安全的使用這些對象

    2.線程安全的:immutable對象在多線程下安全,沒有競态條件

    3.不需要支援可變性, 可以盡量節省空間和時間的開銷. 所有的不可變集合實作都比可變集合更加有效的利用記憶體 (analysis)

    4.可以被使用為一個常量,并且期望在未來也是保持不變的

  immutable對象可以很自然地用作常量,因為它們天生就是不可變的對于immutable對象的運用來說,它是一個很好的防禦程式設計(defensive programming)的技術實踐。

  JDK中實作immutable集合

  在JDK中提供了Collections.unmodifiableXXX系列方法來實作不可變集合, 但是存在一些問題,下面我們先看一個具體執行個體:

 

 總結一下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類

對于排序的集合來說有例外,因為元素的順序在建構集合的時候就被固定下來了。譬如,ImmutableSet.of(“a”, “b”, “c”, “a”, “d”, “b”),對于這個集合的周遊順序來說就是”a”, “b”, “c”, “d”。

更智能的copyOf

  copyOf方法比你想象的要智能,ImmutableXXX.copyOf會在合适的情況下避免拷貝元素的操作-先忽略具體的細節,但是它的實作一般都是很“智能”的。譬如

在這段代碼中,ImmutableList.copyOf(imSet)會智能地傳回時間複雜度為常數的ImmutableSet的imSet.asList()。

  一般來說,ImmutableXXX.copyOf(ImmutableCollection)會避免線性複雜度的拷貝操作。如在以下情況:

  這個操作有可能就利用了被封裝資料結構的常數複雜度的操作。但例如ImmutableSet.copyOf(list)不能在常數複雜度下實作。

  這樣不會導緻記憶體洩漏-例如,你有個ImmutableList 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這樣的方法。

  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