java8 Optional
這篇文章主要結合原始碼去理解學習Optional類,本人能力有限,或許有些地方不能理解,希望能有大佬解惑
java8 引入了一個比較有趣的特性--Optional類,ta主要用來解決空指標異常的問題
1.建立Optional
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
private Optional() {
this.value = null ;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
由於Optional類中構造方法都是private許可權的 所以只能根據下列方法獲取Optional例項
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
empty() 建立一個value為null的的例項,(@SuppressWarnings("unchecked") 為忽略警告,在這裡我們不要管他)
of(T value) 內部呼叫了建構函式,通過檢視建構函式,發現呼叫了Objects.requireNonNull(value),檢查是否為空,如果為空丟擲NullPointerException,所以我們可以得出結論: of() 只能建立非空值,當確定value不為null時,我們才能通過 Optional.of(value) 來得到包含value的Optional例項
ofNullable(T value) 通過方法內部程式碼可以看出和of(T value)的區別只是當value為 null 時,ofNullable返回EMPTY物件
由此可以看出,在開發中用到ofNullable的機會比of大很多
程式碼:
Optional<Object> empty = Optional.empty();
Optional<String> _nonNull = Optional.of("_NonNull");
Optional<Object> _null = Optional.ofNullable(null);
補充:Optional其實就是一個包裝類,可以裝空值和非空值,可以解決很多場景下的空指標異常
2.訪問Optional
@NotNull @Contract(pure=true)public T get() { if (value == null) { throw new NoSuchElementException("No value present"); } return value; } public boolean isPresent() { return value != null; } public void ifPresent(Consumer<? super T> consumer) { if (value != null) consumer.accept(value); } public Optional<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); } 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)); } } public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Objects.requireNonNull(mapper.apply(value)); } } public T orElse(T other) { return value != null ? value : other; } public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); } public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throw exceptionSupplier.get(); } }
@NotNull @Contract(pure=true) 為什麼會出現在這裡?
程式碼都很簡單
get() 獲取值,空值拋異常
isPresent() 判斷值是否存在
ifPresent(Consumer<? super T> consumer)傳入一個消費者,如果值存在就執行lambda表示式
filter(Predicate<? super T> predicate) 傳入謂詞進行過濾,如果value滿足條件則返回,不滿足返回EMPTY
map(Function<? super T, ? extends U> mapper),flatMap(Function<? super T, Optional<U>> mapper) 兩個方法都是對Optional中的值進行一系列操作,通過實現Function的lambda表示式傳入操作,通過原始碼可以看出,二者都要求Optional的值非空才能執行mapping函式,二者都返回Optional物件,但map會自動將結果封裝為Optional物件,flatMap則需要手動封裝到Optional
orElse(T other),orElseGet(Supplier<? extends T> other) 設定預設值,當value為空時,orElse返回引數值,orElseGet返回Supplier介面的執行結果,當value有值時,二者都返回value,區別在於orElse的預設值為引數,即在呼叫orElse時預設值已經存在,而orElseGet預設值是介面實現生成,引數為生成預設值的手段,即當呼叫orElseGet時,預設值還沒有生成,只提供了生成預設值的方法,在value為空時才生成預設值。
orElseThrow(Supplier<? extends X> exceptionSupplier) 當value為空時,丟擲異常,自己決定丟擲異常型別,而不是總丟擲NullPointerException
_nonNull.ifPresent(System.out::println);
Optional<Boolean> aBoolean = _nonNull.map(non -> non.contains("o"));
Optional<Boolean> aBoolean1 = aBoolean.filter(Boolean::booleanValue);