[Immutable](http://www.iteblog.com/archives/tag/immutable "查看 Immutable 中的全部文章")中文意思就是不可變。那為什么需要構建一個不可變的對象?原因有以下幾點:
1. 在并發程序中,使用[Immutable](http://www.iteblog.com/archives/tag/immutable "查看 Immutable 中的全部文章")既保證線程安全性,也大大增強了并發時的效率(跟并發鎖方式相比)。尤其當一個對象是值對象時,更應該考慮采用[Immutable](http://www.iteblog.com/archives/tag/immutable "查看 Immutable 中的全部文章")方式;
1. 被不可信的類庫使用時會很安全;
1. 如果一個對象不需要支持修改操作(mutation),將會節省空間和時間的開銷;經過分析,所有不可變的集合實現都比可變集合更加有效地利用內存;
1. 可以當作一個常量來對待,并且這個對象在以后也不會被改變。
將一個對象復制一份成immutable的,是一個防御性編程技術。在JDK類庫中很多集合(List、Set、Map等)都可以調用Collections類提供的靜態方法unmodifiableXXX(…)來得到一個不可修改的視圖,如下所示:
~~~
List list = new ArrayList();
list.add("wyp");
list.add("good");
List unmodifiableList = Collections.unmodifiableList(list);
System.out.println(unmodifiableList);//[wyp, good]
unmodifiableList.add("add");
~~~
上述代碼利用Collections.unmodifiableList(list)得到一個不可修改的集合unmodifiableList,當unmodifiableList.add(“add”)時,運行代碼將會出現以下異常:
~~~
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableCollection.add(Collections.java:1018)
at com.wyp.test.testFiles(test.java:152)
at com.wyp.test.main(test.java:160)
~~~
一切看起來很不錯,因為調用unmodifiableList.add()會拋出一個java.lang.UnsupportedOperationException。但,如果有用戶修改了list,會發生什么情況?在上述代碼的下面加入以下代碼:
~~~
list.add("add");
System.out.println(unmodifiableList);
~~~
當你再次打印unmodifiableList的時候,你會發現結果是[wyp, good, add],多了一個add元素。unmodifiableList不是不可變的嗎?這顯然不是我們期望的。
> 說明:Collections.unmodifiableList(…)實現的不是真正的[不可變集合](http://www.iteblog.com/archives/tag/%e4%b8%8d%e5%8f%af%e5%8f%98%e9%9b%86%e5%90%88 "查看 不可變集合 中的全部文章"),當原始集合被修改后,[不可變集合](http://www.iteblog.com/archives/tag/%e4%b8%8d%e5%8f%af%e5%8f%98%e9%9b%86%e5%90%88 "查看 不可變集合 中的全部文章")里面的元素也是跟著發生變化。
利用JDK類庫中提供的unmodifiableXXX方法最少存在以下幾點不足:
1. 笨拙:因為你每次都得寫那么多代碼;
1. 不安全:如果沒有引用到原來的集合,這種情況之下才會返回唯一真正永恒不變的集合;
1. 效率很低:返回的不可修改的集合數據結構仍然具有可變集合的所有開銷。
[Guava](http://www.iteblog.com/archives/tag/guava "查看 Guava 中的全部文章")類庫中提供的Immutable才是真正的不可修改的集合。
~~~
import com.google.common.collect.ImmutableList;
ImmutableList immutableList = ImmutableList.of("wyp", "good");
~~~
當你往immutableList 中添加元素,也會拋出java.lang.UnsupportedOperationException異常。可以用ImmutableList提供的以下幾個方法來得到一個不可變的集合:
copyOf(Collection<? extends E> elements)比如ImmutableList.copyOf(list);
用of()方法得到一個空的不可變的List(ImmutableList提供了很多of()的重寫);
利用Builder來實現:
~~~
List list = new ArrayList();
list.add("wyp");
list.add("good");
ImmutableList GOOGLE_IMMUTABLE = ImmutableList
. builder().addAll(list).add("add").build();
~~~
JDK和[Guava](http://www.iteblog.com/archives/tag/guava "查看 Guava 中的全部文章")提供的不可變類型:
| 可變集合類型 | JDK?or?Guava? | Guava[不可變集合](http://www.iteblog.com/archives/tag/%e4%b8%8d%e5%8f%af%e5%8f%98%e9%9b%86%e5%90%88 "查看 不可變集合 中的全部文章") |
|-----|-----|-----|
| 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 |
轉載請注明: 轉載自[過往記憶(http://www.iteblog.com/)](http://www.iteblog.com/)
本文鏈接地址:?[Guava學習之Immutable集合(http://www.iteblog.com/archives/524)](http://www.iteblog.com/archives/524)