天天看點

Java 8中 Optional 類源碼實作與分析

這是《水煮 JDK 源碼》系列 的第9篇文章,計劃撰寫100篇關于JDK源碼相關的文章

Optional

類位于

java.util

包下,自 JDK 1.8 版本新增的,它是一個 final 類,不能被繼承,且構造函數是 private 的,不能被執行個體化,它提供了一系列對 null 空值的處理方法,是一個包裝類,既可以包裝非空對象,也可以包裝空值,下面來看看它的定義以及預設構造函數。

public final class Optional<T> {
    private Optional() {
        this.value = null;
    }
}
           

衆所周知,在Java開發過程中,經常需要對

null

進行判斷和處理,如果漏掉了,就會引發

NullPointerException

異常,是以

null

判斷幾乎會遍布在代碼的每個角落,那麼神奇的

null

是如何誕生的呢?

1965年,英國一位名為Tony Hoare的計算機科學家在設計ALGOL W語言時提出了null引用的想法。ALGOL W是第一批在堆上配置設定記錄的類型語言之一。Hoare選擇null引用這種方式,“隻是因為這種方法實作起來非常容易”。雖然他的設計初衷就是要“通過編譯器的自動檢測機制,確定所有使用引用的地方都是絕對安全的”,他還是決定為null引用開個綠燈,因為他認為這是為“不存在的值”模組化最容易的方式。很多年後,他開始為自己曾經做過這樣的決定而後悔不疊,把它稱為“我價值百萬的重大失誤”。(引自網絡)

其實,

null

引入的目的是為了表示變量值的缺失。

那麼在Java 8 中為什麼會引入這樣的一個

Optional

類呢?主要是為了對存在或缺失的變量值模組化,這樣一來,不管變量有沒有值,都可以統一使用

Optional

來表示,它可以減少

null

值的判斷邏輯,使得代碼結構更加簡單,同時也可以減少

NullPointerException

異常的出現。

1、構造函數

Optional

類提供了兩個構造函數,都是

private

的,如下:

private Optional() {
    this.value = null;
}

private Optional(T value) {
    // value 值不能為 null,否則會抛出空指針異常
    this.value = Objects.requireNonNull(value);
}
           

因為構造函數是私有的,是以不能直接執行個體化

Optional

類,那麼如果建立

Optional

執行個體呢?可以通過以下的三個方法:

  • empty()

    :通過靜态工廠方法建立一個空的

    Optional

    執行個體;
  • of()

    :将指定值用

    Optional

    封裝之後傳回,如果該值為

    null

    ,則抛出一個

    NullPointerException

    異常;
  • ofNullable()

    :将指定值用

    Optional

    封裝之後傳回,如果該值為

    null

    ,則傳回一個空的

    Optional

    對象;

2、方法

Optional

類提供了一些方法,主要分為 靜态方法和執行個體方法,像上面提到的三個方法,都是靜态方法,主要用于建立

Optional

執行個體。

2.1 靜态方法

(1)empty()

empty()

方法是通過靜态工廠方法建立一個空的

Optional

執行個體,不包含任何值,其定義如下:

private static final Optional<?> EMPTY = new Optional<>();

public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}
           

如果直接調用

empty()

方法,将會直接傳回靜态常量

EMPTY

.

(2)of()

of()

方法将指定值用

Optional

封裝之後傳回,如果該值為

null

,則抛出一個

NullPointerException

異常,其源碼如下:

public static <T> Optional<T> of(T value) {
    return new Optional<>(value);
}
           

直接是通過

new Optional(T value)

方法建立執行個體,該構造方法使用

Objects.requireNonNull()

對傳入的參數進行檢查,其源碼如下:

public static <T> T requireNonNull(T obj) {
    if (obj == null)
        throw new NullPointerException();
    return obj;
}
           

也就是說

of()

方法不接受

null

空值。

(3)ofNullable()

ofNullable()

方法将指定值用

Optional

封裝之後傳回,如果該值為

null

,則傳回一個空的

Optional

對象,其定義如下:

public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}
           

從實作可以看出,

ofNullable()

方法可以接受

null

空值,而

of()

方法不能接收空值,這也是它與

of()

方法之間的差別。

2.2 執行個體方法

(1)get()

get()

方法是用來擷取

Optional

封裝的值的,如果該值存在,将該值用

Optional

封裝傳回,否則抛出一個

NoSuchElementException

異常,其定義如下:

public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}
           

其中的

value

值是

Optional

中的成員變量,其定義如下:

private final T value;
           

(2)isPresent()

isPresent()

方法用于判斷

value

值是否存在,如果值存在就傳回true,否則傳回false,其定義如下:

public boolean isPresent() {
    return value != null;
}
           

(3)ifPresent()

ifPresent()

方法也是用于判斷

value

值是否存在,如果值存在,就執行使用該值的方法調用,否則什麼也不做,其定義如下:

public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
        consumer.accept(value);
}
           

該方法的參數是

Consumer

,如果

value

值存在,則會傳入到

Consumer.accept()

方法中,其中

Consumer

類是一個功能性接口,其定義如下:

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}
           

(4)filter()

filter()

方法主要用于條件過濾,如果值存在并且滿足提供的謂詞,就傳回包含該值的

Optional

對象;否則傳回一個空的

Optional

對象,其定義如下:

public Optional<T> filter(Predicate<? super T> predicate) {
    // filter 方法中的謂詞參數不能為空,否則會抛出空指針異常
    Objects.requireNonNull(predicate);
    if (!isPresent())
        return this;
    else
        return predicate.test(value) ? this : empty();
}
           

filter()

方法的參數是需要傳入一個

Predicate

謂詞,并且參數不能為

null

,否則會抛出

NullPointerException

異常,當

value

值存在時,會調用

Predicate.test()

方法進行判斷。

(5)map()

map()

方法主要是對

Optional

封裝的值執行

mapping

函數,如果值存在,就對該值執行提供的mapping函數調用,如果值不存在,則直接傳回空的

Optional

對象,其定義如下:

public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    // map 方法中的參數 mapper 函數不能為空,否則會抛出空指針異常
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Optional.ofNullable(mapper.apply(value));
    }
}
           

(6)flatMap()

flatMap()

方法主要也是對

Optional

封裝的值執行

mapping

函數,如果值存在,就對該值執行提供的mapping函數調用,傳回一個

Optional

類型的值,否則就傳回一個空的

Optional

對象,其定義如下:

public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    // flatMap 方法中的參數 mapper 函數不能為空,否則會抛出空指針異常
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Objects.requireNonNull(mapper.apply(value));
    }
}
           

flatMap()

方法和

map()

方法有什麼差別呢?從方法定義的參數

(7)orElse()

orElse()

方法主要用于如果有值,直接傳回,如果沒有值時,則傳回該方法設定的預設值,其源碼如下:

public T orElse(T other) {
    return value != null ? value : other;
}
           

(8)orElseGet()

orElseGet()

方法和

orElse()

方法的作用類似,隻是當沒有值時,

orElseGet()

方法不是直接傳回一個值,而是一個由指定的

Supplier

接口傳回的值,其定義如下:

public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
}
           

(9)orElseThrow()

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    // 如果值不為 null,直接傳回
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}
           

3、其他相關類

  • OptionalInt

    :用于包裝整型類;
  • OptionalLong

    :用于包裝長整型類;
  • OptionalDouble

    :用于包裝Double類型;