java併發編程——不可變對象

不可變類

不可變類:指這個類的實例一旦建立完成後,就不能改變其成員變量值。如JDK內部自帶的8個包裝類和String類都是不可變類(Interger、Long和String等)都是不可變類。因此不可變類並非指該類是被final修飾的,而是指該類的全部屬性是被final修飾的java

可變類:相對於不可變類,可變類建立實例後能夠改變其成員變量值,開發中建立的大部分類都屬於可變類。編程

java中自定義不可變類應該遵照以下原則:緩存

  1. 使用private和final修飾符來修飾該類的屬性。
  2. 提供帶參數的構造器,用於根據傳入的參數來初始化屬性。
  3. 僅爲該類屬性提供getter方法,不要提供setter方法。
  4. 若是有必要,重寫hashCode和equals方法,同時應保證兩個用equals方法判斷爲相等的對象,其hashCode也應相等。

使用不可變類的好處?安全

  1. Immutable對象是線程安全的,能夠不用被synchronize就在併發環境中共享
  2. Immutable對象簡化了程序開發,由於它無需使用額外的鎖機制就能夠在線程間共享
  3. Immutable對象提升了程序的性能,由於它減小了synchroinzed的使用
  4. Immutable對象是能夠被重複使用的,你能夠將它們緩存起來重複使用,就像字符串字面量和整型數字同樣。你可使用靜態工廠方法來提供相似於valueOf()這樣的方法,它能夠從緩存中返回一個已經存在的Immutable對象,而不是從新建立一個。

immutable對象也有一個缺點就是會製造大量垃圾,因爲他們不能被重用並且對於它們的使用就是」用「而後」扔「,字符串就是一個典型的例子,它會創造不少的垃圾,給垃圾收集帶來很大的麻煩。固然這只是個極端的例子,合理的使用immutable對象會創造很大的價值。併發

不可變集合

一、JDK中實現immutable集合

在JDK中提供了Collections.unmodifiableXXX系列方法來實現不可變集合, 而jdk對不可變集合是經過拋出異常來實現的。可是存在一些問題,下面咱們先看一個具體實例:性能

public class ImmutableTest {

    @Test
    public void testJDKImmutable(){
        List<String> list=new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("c");

        //經過list建立一個不可變的unmodifiableList集合
        List<String> unmodifiableList=Collections.unmodifiableList(list);
        System.out.println(unmodifiableList);

        //經過list添加元素
        list.add("ddd");
        System.out.println("往list添加一個元素:"+list);
        System.out.println("經過list添加元素以後的unmodifiableList:"+unmodifiableList);

        //經過unmodifiableList添加元素
        unmodifiableList.add("eee");
        System.out.println("往unmodifiableList添加一個元素:"+unmodifiableList);

    }
}

··············································································
運行結果:
[a, b, c]
往list添加一個元素:[a, b, c, ddd]
經過list添加元素以後的unmodifiableList:[a, b, c, ddd]

java.lang.UnsupportedOperationException
    at java.util.Collections$UnmodifiableCollection.add(Collections.java:1055)
    at dawn.thread.ImmutableTest.testJDKImmutable(ImmutableTest.java:31)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

經過運行結果咱們能夠看出:雖然unmodifiableList不能夠直接添加元素,可是個人list是能夠添加元素的,而list的改變也會使unmodifiableList改變。ui

因此說Collections.unmodifiableList實現的不是真正的不可變集合。線程

二、Guava的immutable集合

Guava提供了對JDK裏標準集合類裏的immutable版本的簡單方便的實現,以及Guava本身的一些專門集合類的immutable實現。當你不但願修改一個集合類,或者想作一個常量集合類的時候,使用immutable集合類就是一個最佳的編程實踐。code

注意:每一個Guava immutable集合類的實現都拒絕null值。咱們作過對Google內部代碼的全面的調查,而且發現只有5%的狀況下集合類容許null值,而95%的狀況下都拒絕null值。萬一你真的須要能接受null值的集合類,你能夠考慮用Collections.unmodifiableXXX。對象

immutable集合能夠有如下幾種方式來建立:

  1. 用copyOf方法, ImmutableSet.copyOf(set)
  2. 使用of方法,ImmutableSet.of("a", "b", "c")或者ImmutableMap.of("a", 1, "b", 2)
  3. 使用Builder類

Guava的immutale集合的簡單使用

@Test
    public void testGuavaImmutable(){

        List<String> list=new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("c");

        ImmutableList<String> imlist=ImmutableList.copyOf(list);
        System.out.println("imlist:"+imlist);

        ImmutableList<String> imOflist=ImmutableList.of("peida","jerry","harry");
        System.out.println("imOflist:"+imOflist);

        ImmutableSortedSet<String> imSortList=ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");
        System.out.println("imSortList:"+imSortList);

        list.add("baby");
        //關鍵看這裏是否imlist也添加新元素了
        System.out.println("list添加新元素以後看imlist:"+imlist);

        ImmutableSet<Color> imColorSet =
                ImmutableSet.<Color>builder()
                        .add(new Color(0, 255, 255))
                        .add(new Color(0, 191, 255))
                        .build();

        System.out.println("imColorSet:"+imColorSet);
    }
------------------------------------------------------------------------------
運行結果:
imlist:[a, b, c]
imOflist:[peida, jerry, harry]
imSortList:[a, b, c, d]
list添加新元素以後看imlist:[a, b, c]
imColorSet:[java.awt.Color[r=0,g=255,b=255], java.awt.Color[r=0,g=191,b=255]]

更智能的copyOf

copyOf方法比你想象的要智能,ImmutableXXX.copyOf會在合適的狀況下避免拷貝元素的操做-先忽略具體的細節,可是它的實現通常都是很「智能」的。譬如:

@Test
    public void testCotyOf(){
        ImmutableSet<String> imSet=ImmutableSet.of("peida","jerry","harry","lisa");
        System.out.println("imSet:"+imSet);

        //set直接轉list
        ImmutableList<String> imlist=ImmutableList.copyOf(imSet);
        System.out.println("imlist:"+imlist);

        //list直接轉SortedSet
        ImmutableSortedSet<String> imSortSet=ImmutableSortedSet.copyOf(imSet);
        System.out.println("imSortSet:"+imSortSet);

        List<String> list=new ArrayList<String>();
        for(int i=0;i<=10;i++){
            list.add(i+"x");
        }
        System.out.println("list:"+list);

        //截取集合部分元素
        ImmutableList<String> imInfolist=ImmutableList.copyOf(list.subList(2, 8));
        System.out.println("imInfolist:"+imInfolist);
    }
----------------------------------------------------------------------------
運行結果:
imSet:[peida, jerry, harry, lisa]
imlist:[peida, jerry, harry, lisa]
imSortSet:[harry, jerry, lisa, peida]
list:[0x, 1x, 2x, 3x, 4x, 5x, 6x, 7x, 8x, 9x, 10x]
imInfolist:[2x, 3x, 4x, 5x, 6x, 7x]

ImmutableMap使用舉例

public class ImmutableExample3 {

    private final static ImmutableList<Integer> list = ImmutableList.of(1, 2, 3);
    private final static ImmutableSet set = ImmutableSet.copyOf(list);
    private final static ImmutableMap<Integer, Integer> map = ImmutableMap.of(1, 2, 3, 4);//map必須成對出現(偶數個)
    private final static ImmutableMap<Integer, Integer> map2 = ImmutableMap.<Integer, Integer>builder().put(1, 2).put(3, 4).put(5, 6).build();

    public static void main(String[] args) {
        System.out.println(map2.get(3));
    }
}
相關文章
相關標籤/搜索