天天看點

[Guava源碼日報](5)Optional分析

版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。 https://blog.csdn.net/SunnyYoona/article/details/71079708

大多數情況下,開發人員使用null表明的是某種缺失情形:可能是已經有一個預設值,或沒有值,或找不到值。例如,Map.get傳回null就表示找不到給定鍵對應的值或者給定鍵對應值就是為null。

Guava用Optional表示可能為null的T類型引用。一個Optional執行個體可能包含非null的引用(我們稱之為引用存在),也可能什麼也不包括(稱之為引用缺失)。它從不說包含的是null值,而是用存在或缺失來表示。但Optional從不會包含null值引用。

1. 主要方法 http://gitlab.corp.qunar.com/jifeng.si/learningnotes/blob/master/IT/Java/Guava/%5BGuava%E6%BA%90%E7%A0%81%E6%97%A5%E6%8A%A5%5D%EF%BC%885%EF%BC%89Optional%E5%88%86%E6%9E%90.md#1

1.1 建立Optional執行個體 (靜态方法) http://gitlab.corp.qunar.com/jifeng.si/learningnotes/blob/master/IT/Java/Guava/%5BGuava%E6%BA%90%E7%A0%81%E6%97%A5%E6%8A%A5%5D%EF%BC%885%EF%BC%89Optional%E5%88%86%E6%9E%90.md#1-1-optional

方法 描述
Optional.of(T) 建立指定引用的Optional執行個體,若引用為null則快速失敗。
Optional.absent(T) 建立引用缺失的Optional執行個體。
Optional.fromNullable(T) 建立指定引用的Optional執行個體,若引用為null則表示缺失。

1.2 使用Optional執行個體查詢引用(非靜态方法) http://gitlab.corp.qunar.com/jifeng.si/learningnotes/blob/master/IT/Java/Guava/%5BGuava%E6%BA%90%E7%A0%81%E6%97%A5%E6%8A%A5%5D%EF%BC%885%EF%BC%89Optional%E5%88%86%E6%9E%90.md#1-2-optional

boolean isPresent(T) 如果Optional包含非null的引用,引用存在,傳回true
T get(T) 傳回Optional所包含的引用,若引用缺失,則抛出java.lang.IllegalStateException
T or(T) 傳回Optional所包含的引用,若引用缺失,傳回指定的值
T orNull() 傳回Optional所包含的引用,若引用缺失,傳回null
Set asSet() 傳回Optional所包含引用的單例不可變集,如果引用存在,傳回一個隻有單一進制素的集合,如果引用缺失,傳回一個空集合。

2. 使用意義 http://gitlab.corp.qunar.com/jifeng.si/learningnotes/blob/master/IT/Java/Guava/%5BGuava%E6%BA%90%E7%A0%81%E6%97%A5%E6%8A%A5%5D%EF%BC%885%EF%BC%89Optional%E5%88%86%E6%9E%90.md#2

使用Optional除了賦予null語義,增加了可讀性,最大的優點在于它是一種傻瓜式的防護。Optional迫使你積極思考引用缺失的情況,因為你必須顯式地從Optional擷取引用。直接使用null很容易讓人忘掉某些情形。

如同輸入參數,方法的傳回值也可能是null。和其他人一樣,你絕對很可能會忘記别人寫的方法method(a,b)會傳回一個null,就好像當你實作method(a,b)時,也很可能忘記輸入參數a可以為null。将方法的傳回類型指定為Optional,也可以迫使調用者思考傳回的引用缺失的情形。

3. 類聲明 http://gitlab.corp.qunar.com/jifeng.si/learningnotes/blob/master/IT/Java/Guava/%5BGuava%E6%BA%90%E7%A0%81%E6%97%A5%E6%8A%A5%5D%EF%BC%885%EF%BC%89Optional%E5%88%86%E6%9E%90.md#3

@GwtCompatible(serializable = true)
public abstract class Optional<T> implements Serializable
           

4. 分析 http://gitlab.corp.qunar.com/jifeng.si/learningnotes/blob/master/IT/Java/Guava/%5BGuava%E6%BA%90%E7%A0%81%E6%97%A5%E6%8A%A5%5D%EF%BC%885%EF%BC%89Optional%E5%88%86%E6%9E%90.md#4

4.1 Optional.of(T) http://gitlab.corp.qunar.com/jifeng.si/learningnotes/blob/master/IT/Java/Guava/%5BGuava%E6%BA%90%E7%A0%81%E6%97%A5%E6%8A%A5%5D%EF%BC%885%EF%BC%89Optional%E5%88%86%E6%9E%90.md#4-1-optional-of-t

public void test1(){
        Integer num = null;
        Optional<Integer> op1 = Optional.of(num); // java.lang.NullPointerException
        System.out.println(op1.get());
    }
           

上面的程式,我們使用Optional.of(null)方法,這時候程式會第一時間抛出空指針異常,這可以幫助我們盡早發現問題。如果給定值不為null,則會傳回給定值的Optional執行個體。

源碼

public static <T> Optional<T> of(T reference) {
    return new Present<T>(checkNotNull(reference));
  }
           

首先使用checkNotNull來判斷給定值是否為null,如果為null,則會抛出空指針異常,否則傳回給定值的Optional的執行個體(Present是Optional的子類)。

4.2 Optional.absent() http://gitlab.corp.qunar.com/jifeng.si/learningnotes/blob/master/IT/Java/Guava/%5BGuava%E6%BA%90%E7%A0%81%E6%97%A5%E6%8A%A5%5D%EF%BC%885%EF%BC%89Optional%E5%88%86%E6%9E%90.md#4-2-optional-absent

public void test3(){
        Integer num = new Integer(4);
        Optional<Integer> op = Optional.absent();
        Optional<Integer> op2 = Optional.of(num);
        System.out.println("op:" + op.isPresent() + "    op2:" + op2.isPresent());
    }
           

上面的程式,我們使用Optional.absent()方法,建立引用缺失的Optional執行個體。 源碼:

public static <T> Optional<T> absent() {
    return Absent.withType();
  }
           

Absent是Optional的子類:

static final Absent<Object> INSTANCE = new Absent<Object>();
  @SuppressWarnings("unchecked") // implementation is "fully variant"
  static <T> Optional<T> withType() {
    return (Optional<T>) INSTANCE;
  }
           

通過withType方法傳回一個靜态Absent對象,并強制轉換為Optional對象。從上面就可以看出其中不包含任何的引用。

4.3 Optional.fromNullable(T) http://gitlab.corp.qunar.com/jifeng.si/learningnotes/blob/master/IT/Java/Guava/%5BGuava%E6%BA%90%E7%A0%81%E6%97%A5%E6%8A%A5%5D%EF%BC%885%EF%BC%89Optional%E5%88%86%E6%9E%90.md#4-3-optional-fromnullable-t

建立指定引用的Optional執行個體,若引用為null則表示缺失,傳回應用缺失對象Absent,否則傳回引用存在對象Present。

public void test4(){
        Integer num1 = null;
        Integer num2 = new Integer(4);
        Optional<Integer> op1 = Optional.fromNullable(num1); // 引用缺失
        Optional<Integer> op2 = Optional.fromNullable(num2); // 引用存在
        System.out.println("op1:" + op1.isPresent() + "    op2:" + op2.isPresent()); // false true
    }
}
           

源碼:

public static <T> Optional<T> fromNullable(@Nullable T nullableReference) {
    return (nullableReference == null)
        ? Optional.<T>absent()
        : new Present<T>(nullableReference);
  }
           

從上面源碼中可以看出如果T為null,則調用Optional靜态方法absent(),表示引用缺失;如果T不為null,則建立一個Present對象,表示引用存在。

4.4 T get() http://gitlab.corp.qunar.com/jifeng.si/learningnotes/blob/master/IT/Java/Guava/%5BGuava%E6%BA%90%E7%A0%81%E6%97%A5%E6%8A%A5%5D%EF%BC%885%EF%BC%89Optional%E5%88%86%E6%9E%90.md#4-4-t-get

傳回Optional包含的T執行個體,該T執行個體必須不為空;否則,對包含null的Optional執行個體調用get()會抛出一個IllegalStateException異常。

public void test5(){
        Integer num1 = null;
        Integer num2 = new Integer(4);
        Optional<Integer> op1 = Optional.fromNullable(num1); // 引用缺失
        Optional<Integer> op2 = Optional.fromNullable(num2); // 引用存在
        System.out.println("op2:" + op2.get()); // 4
        System.out.println("op1:" + op1.get()); // java.lang.IllegalStateException: Optional.get() cannot be called on an absent value
    }
           

因為fromNullable對象根據給定值是否為null,傳回不同的對象:

return (nullableReference == null)
        ? Optional.<T>absent()
        : new Present<T>(nullableReference);
           

是以調用的get方法也将會不一樣。

public abstract T get();
           

如果傳回的是一個Present對象,将調用Present類中的get()方法:

@Override
  public T get() {
    return reference;
  }
           

如果傳回的是一個Absent對象,将調用Absent類中的get()方法:

@Override
  public T get() {
    throw new IllegalStateException("Optional.get() cannot be called on an absent value");
  }
           

4.5 T or (T) http://gitlab.corp.qunar.com/jifeng.si/learningnotes/blob/master/IT/Java/Guava/%5BGuava%E6%BA%90%E7%A0%81%E6%97%A5%E6%8A%A5%5D%EF%BC%885%EF%BC%89Optional%E5%88%86%E6%9E%90.md#4-5-t-or-t

傳回Optional所包含的引用,若引用缺失,傳回指定的值。

public void test6(){
        Integer num1 = null;
        Integer num2 = new Integer(4);
        Optional<Integer> op1 = Optional.fromNullable(num1); // 引用缺失
        Optional<Integer> op2 = Optional.fromNullable(num2); // 引用存在
        System.out.println("op2:" + op2.or(0)); // 4
        System.out.println("op1:" + op1.or(0)); // 0
    }
           
return (nullableReference == null)
        ? Optional.<T>absent()
        : new Present<T>(nullableReference);
           

是以調用的or方法也将會不一樣。

public abstract T or(T defaultValue);
           

(1)如果傳回的是一個Present對象,将調用Present類中的or()方法:

@Override
  public T or(T defaultValue) {
    checkNotNull(defaultValue, "use Optional.orNull() instead of Optional.or(null)");
    return reference;
  }
           

這個方法首先對預設值進行判斷,如果不為null,則傳回引用;如果為null,抛出空指針異常,這種情況可以使用Optional.orNull()方法代替。

(2)如果傳回的是一個Absent對象,将調用Absent類中的or()方法:

@Override
  public T or(T defaultValue) {
    return checkNotNull(defaultValue, "use Optional.orNull() instead of Optional.or(null)");
  }
           

這個方法首先對預設值進行判斷,如果不為null,則傳回預設值;如果為null,抛出空指針異常,這種情況可以使用Optional.orNull()方法代替。

public void test6(){
        String num1 = null;
        String num2 = "123";
        String defaultNum = null;
        Optional<String> op1 = Optional.fromNullable(num1); // 引用缺失
        Optional<String> op2 = Optional.fromNullable(num2); // 引用存在
        System.out.println("op2:" + op2.or("0")); // 123
        System.out.println("op1:" + op1.or(defaultNum)); // java.lang.NullPointerException: use Optional.orNull() instead of Optional.or(null)
    }
           

4.6 T orNull() http://gitlab.corp.qunar.com/jifeng.si/learningnotes/blob/master/IT/Java/Guava/%5BGuava%E6%BA%90%E7%A0%81%E6%97%A5%E6%8A%A5%5D%EF%BC%885%EF%BC%89Optional%E5%88%86%E6%9E%90.md#4-6-t-ornull

public void test6(){
        String num1 = null;
        String num2 = "123";
        Optional<String> op1 = Optional.fromNullable(num1); // 引用缺失
        Optional<String> op2 = Optional.fromNullable(num2); // 引用存在
        System.out.println("op2:" + op2.orNull()); // 123
        System.out.println("op1:" + op1.orNull()); // null
    }
           
return (nullableReference == null)
        ? Optional.<T>absent()
        : new Present<T>(nullableReference);
           

是以調用的orNull方法也将會不一樣。

@Nullable
  public abstract T orNull();
           

(1)如果傳回的是一個Present對象,将調用Present類中的orNull()方法:

@Override
  public T orNull() {
    return reference;
  }
           

引用存在,傳回引用。

(2)如果傳回的是一個Absent對象,将調用Absent類中的orNull()方法:

@Override
  @Nullable
  public T orNull() {
    return null;
  }
           

引用缺失,傳回null,此時沒有預設值。

參考文章:

http://ifeve.com/google-guava-using-and-avoiding-null/ http://ifeve.com/google-guava-using-and-avoiding-null/

繼續閱讀