這是《水煮 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
-
:用于包裝Double類型;OptionalDouble