Optional 理解
1. 含義
Optional
是一個容器對象,該容器里可能包含非空值也可能不包含非空值。最主要的用途就是為了規避 NPE 異常(傳入的對象為 null 造成)。
- 如果存在值,通過
isPresent
方法返回 true,通過get
方法獲取 value
Optional
也提供了額外的方法,這些方法根據是否存在 value 來發揮作用。
注意
請不要在 Optional
對象中使用 hashcode
,synchronized
,==
,否則會產生不可預料的影響。因為 Optional
是基於值的類。
基於值的類(Value-based Classes)
關於什么是 Value-based Clases,我找到 Oracle 的一篇官方文檔:Value-based Classes
某些類(如 java.util.Optional 和 java.time.LocalDateTime) 是基於值的。基於值的實例有如下特征:
- 具有 final 屬性,是不可更改的(盡管可能包含對可變對象的引用)
- 具有
equals()
、hashCode()
、toString()
方法的實現,且實現方法僅依賴於實例自身的狀態發生變化,而不依賴外部的對象或變量的狀態- 不使用身份敏感的操作,使用
==
比較兩個實例,使用 hashcode 獲取實例信息,使用synchronized
獲取內部鎖- 兩實例是否相同是根據
equals()
方法而不是==
- 沒有公開的構造方法,而是通過工廠方法(Factory method)來產生實例
- 若兩實例相同,則可以互相替代,且不會有不同的行為
2. Optional 類中方法
2.1 構造方法
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
-
Optional
是一個容器,容器里面包着一個值,這個值是泛型 -
因為構造方法私有化,所以不能通過 new 新建
Optional
對象,只能通過靜態工廠方法構造對象
2.2 創建 Optional 對象方法
-
of
:返回一個容器的值不為 null 的對象,使用該方法要求調用者調用 of 方法時,參數值不為空,否則會拋出 NPE 異常。public static <T> Optional<T> of(T value) { return new Optional<>(value); }
-
ofNullable
:構造一個可能為空,也可能不為空的 optional 對象。public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); }
-
empty
:返回容器的值為 null 的對象public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }
2.3 其他方法
-
isPresent
:判斷該對象是否存在 -
get
:獲取容器的值 -
orElse
:容器值不為空,將 value 打印出來;為空,返回指定值。public T orElse(T other) { return value != null ? value : other; }
-
orElseGet
:該方法不接受參數。容器值不為空,返回 value;為空,返回指定值public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); }
舉例:
System.out.println(optional.orElseGet(() -> "nihao"));
-
orElseThrow
:容器值不為空,返回 value;為空,拋出異常。 -
map
:映射,將一個值映射成另一個值。如果有值,則對其執行調用映射函數得到返回值。如果返回值不為 null ,則創建包含映射返回值的Optional
作為map
方法返回值,否則返回空Optional
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Optional.ofNullable(mapper.apply(value)); } }
舉例:
System.out.println(optional.map(thecompant -> theCompany.getEmployees()). orElse(Collections.emptylist()));
注意
在企業開發中,我們經常通過 orElse
來規避 NPE 異常。
3. Optional 對象不應該作為方法參數
Optional
無法被序列化。所以不要試圖將 Optional
作為方法參數進行定義,也不要在類當中聲明 Optional
類型的成員變量。Optional
通常只作為方法的返回值,用來規避空指針異常。
在使用 Optional
時,應該使用函數式的編程風格。