一、Optional類的來源
到目前為止,臭名昭著的空指針異常是導(dǎo)致Java應(yīng)用程序失敗的最常見原因。以前,為了解決空指針異常,Google公司著名的Guava項(xiàng)目引入了Optional類,Guava通過使用檢查空值的方式來防止代碼污染,它鼓勵(lì)程序員寫更干凈的代碼。受到Google Guava的啟發(fā),Optional類已經(jīng)成為Java 8類庫的一部分。
二、Optional 簡介
Optional 類(java.util.Optional) 是一個(gè)容器類,它可以保存類型T的值,代表這個(gè)值存在?;蛘邇H僅保存null,表示這個(gè)值不存在。原來用 null 表示一個(gè)值不存在,現(xiàn)在 Optional 可以更好的表達(dá)這個(gè)概念。并且可以避免空指針異常。
Optional 提供很多有用的方法,能幫助我們將 Java 中的對象等一些值存入其中,這樣我們就不用顯式進(jìn)行空值檢測,使我們能夠用少量的代碼完成復(fù)雜的流程。
可以說,使用 Optional 可以幫助我們解決業(yè)務(wù)中,減少值動(dòng)不動(dòng)就拋出空指針異常問題,也減少 null 值的判斷,提高代碼可讀性等,這里我們介紹下,如何使用這個(gè) Optional 類。

三、Optional 類描述
Optional類的Javadoc描述如下:
- 這是一個(gè)可以為null的容器對象。
- 如果值存在則isPresent()方法會(huì)返回true,調(diào)用get()方法會(huì)返回該對象。
- 如果值不存在則isPresent()方法會(huì)返回false,調(diào)用get()方法會(huì)NPE。
3.1 創(chuàng)建Optional類對象的方法
- Optional.of(T t):創(chuàng)建一個(gè) Optional 實(shí)例,t必須非空;
- Optional.empty():創(chuàng)建一個(gè)空的 Optional 實(shí)例
- Optional.ofNullable(T t):t可以為null
public final class Optional<T> {
/**
* 返回一個(gè)空的Optional實(shí)例。 此Optional沒有值。
*
* 類型參數(shù):<T> –不存在的值的類型
* 返回值:一個(gè)空的Optional
* api注意:盡管這樣做可能很誘人,但應(yīng)通過將==與Optional.empty()返回的實(shí)例進(jìn)行比較來避免測試對象是否為空。
* 不能保證它是一個(gè)單例。
* 而是使用isPresent()
*/
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
/**
* 返回一個(gè)Optional描述給定的非null值。
*
* 參數(shù):value –要描述的值,必須為非null
* 類型參數(shù):<T> –值的類型
* 返回值:存在值的Optional
*/
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
/**
* 返回一個(gè)描述給定值的Optional ,如果不為null ,則返回一個(gè)空的Optional。
*
* 參數(shù):值–描述的可能為null值
* 類型參數(shù):<T> –值的類型
* 返回值:一個(gè)Optional與如果指定值是非當(dāng)前值null ,否則一個(gè)空Optional
*/
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
}
3.2 Optional API 歸類
3.2.1 判斷Optional容器中是否包含對象
- boolean isPresent():判斷是否包含對象
- void ifPresent(Consumer<? super T> consumer):如果有值,就執(zhí)行Consumer接口的實(shí)現(xiàn)代碼,并且該值會(huì)作為參數(shù)傳給它。
3.2.2 獲取Optional容器的對象
- T get():如果調(diào)用對象包含值,返回該值,否則拋異常
- T orElse(T other):如果有值則將其返回,否則返回指定的other對象。
- T orElseGet(Supplier<? extends T> other):如果有值則將其返回,否則返回由Supplier接口實(shí)現(xiàn)提供的對象。
- T orElseThrow(Supplier<? extends X> exceptionSupplier):如果有值則將其返回,否則拋出由Supplier接口實(shí)現(xiàn)提供的異常。
3.2.3 過濾
- Optional<T> filter(Predicate<? super <T> predicate):如果值存在,并且這個(gè)值匹配給定的 predicate,返回一個(gè)Optional用以描述這個(gè)值,否則返回一個(gè)空的Optional。
3.2.4 映射
- Optional map(Function<? super T,? extends U> mapper):如果有值,則對其執(zhí)行調(diào)用映射函數(shù)得到返回值。如果返回值不為 null,則創(chuàng)建包含映射返回值的Optional作為map方法返回值,否則返回空Optional。
- Optional flatMap(Function<? super T, Optional<U>> mapper):如果值存在,就對該值執(zhí)行提供的mapping函數(shù)調(diào)用,返回一個(gè)Optional類型的值,否則就返回一個(gè)空的Optional對象。
3.3 Optional API 及源碼注解

package java.util;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* 一個(gè)可能包含也可能不包含非null值的容器對象。
* 如果存在值,則isPresent()返回true 。
* 如果不存在任何值,則該對象被視為空,并且isPresent()返回false 。
* 提供了其他取決于所包含值是否存在的方法,例如orElse()(如果不存在值,則返回默認(rèn)值)和ifPresent()(如果存在值, 則執(zhí)行操作)。
* 這是一個(gè)基于值的類;
* 在Optional實(shí)例上使用標(biāo)識(shí)敏感的操作(包括引用等于(==), 標(biāo)識(shí)哈希碼或同步)可能會(huì)產(chǎn)生不可預(yù)測的結(jié)果, 應(yīng)避免使用
*
*/
public final class Optional<T> {
/**
* empty()通用實(shí)例
*/
private static final Optional<?> EMPTY = new Optional<>();
/**
* 如果不為空,則為該值;否則為false。 如果為null,則表示不存在任何值
*/
private final T value;
/**
* 構(gòu)造一個(gè)空實(shí)例。
*
* 注意:通常,每個(gè)VM僅應(yīng)存在一個(gè)空實(shí)例EMPTY
*/
private Optional() {
this.value = null;
}
/**
* 返回一個(gè)空的Optional實(shí)例。 此Optional沒有值。
*
* 類型參數(shù):<T> –不存在的值的類型
* 返回值:一個(gè)空的Optional
* api注意:盡管這樣做可能很誘人,但應(yīng)通過將==與Optional.empty()返回的實(shí)例進(jìn)行比較來避免測試對象是否為空。
* 不能保證它是一個(gè)單例。
* 而是使用isPresent()
*/
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
/**
* 使用描述的值構(gòu)造一個(gè)實(shí)例。
*
* 參數(shù):值–要描述的非null值
* 拋出:NullPointerException如果值為null
*/
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
/**
* 返回一個(gè)Optional描述給定的非null值。
*
* 參數(shù):value –要描述的值,必須為非null
* 類型參數(shù):<T> –值的類型
* 返回值:存在值的Optional
*/
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
/**
* 返回一個(gè)描述給定值的Optional ,如果不為null ,則返回一個(gè)空的Optional。
*
* 參數(shù):值–描述的可能為null值
* 類型參數(shù):<T> –值的類型
* 返回值:一個(gè)Optional與如果指定值是非當(dāng)前值null ,否則一個(gè)空Optional
*/
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
/**
* 如果存在值,則返回該值,否則拋出NoSuchElementException
* 返回值:此Optional描述的非null值
* 拋出:NoSuchElementException如果不存在任何值
* api注意:此方法的首選替代方法是orElseThrow() 。
*/
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
/**
* 如果存在值,則返回true ,否則返回false 。
*
* 返回值:如果存在值,則為true ,否則為false
*/
public boolean isPresent() {
return value != null;
}
/**
* 如果存在值,則使用該值執(zhí)行給定的操作,否則不執(zhí)行任何操作。
*
* 參數(shù):動(dòng)作–要執(zhí)行的動(dòng)作(如果存在值)
*/
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
/**
* 如果存在值,則使用該值執(zhí)行給定的操作,否則執(zhí)行給定的基于空的操作。
* 參數(shù):動(dòng)作–要執(zhí)行的動(dòng)作(如果存在值)emptyAction –要執(zhí)行的基于空的操作(如果不存在任何值)
* 拋出:NullPointerException如果存在一個(gè)值并且給定的操作為null ,或者不存在任何值并且給定的基于空的操作為null
* @since 9
*/
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
if (value != null) {
action.accept(value);
} else {
emptyAction.run();
}
}
/**
* 如果存在一個(gè)值, 并且該值與給定的謂詞匹配,則返回描述該值的Optional,否則返回一個(gè)空的Optional
*
* 參數(shù):謂詞–應(yīng)用于值的謂詞(如果存在)
* 返回值:一個(gè)Optional描述此的值Optional, 如果一個(gè)值存在并且該值給定的謂詞相匹配, 否則一個(gè)空Optional
* 拋出:NullPointerException如果謂詞為null
*/
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
/**
* 如果存在值, 則返回一個(gè)Optional描述(就像by ofNullable)將給定映射函數(shù)應(yīng)用于該值的結(jié)果, 否則返回一個(gè)空的Optional。
* 如果映射函數(shù)返回null結(jié)果, 則此方法返回空的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));
}
}
/**
* 如果存在一個(gè)值,則返回將給定Optional -bearing映射函數(shù)應(yīng)用于該值的結(jié)果,否則返回一個(gè)空的Optional
* 此方法類似于map(Function),但是映射函數(shù)是其結(jié)果已經(jīng)是Optional函數(shù),如果調(diào)用該函數(shù),則flatMap不會(huì)將其包裝在其他Optional
*
* 參數(shù):mapper –應(yīng)用于值的映射函數(shù)(如果存在)
* 類型參數(shù):<U> –映射函數(shù)返回的Optional值的類型
* 返回值:施加的結(jié)果Optional荷瘤映射函數(shù)此的值Optional,如果一個(gè)值存在,否則一個(gè)空Optional
* 拋出:NullPointerException如果映射函數(shù)為null或返回null結(jié)果
*
*/
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));
}
}
/**
* 如果值存在時(shí),返回一個(gè)Optional描述的值,否則將返回一個(gè)Optional產(chǎn)生通過供給功能。
*
* 參數(shù):供應(yīng)商–產(chǎn)生要返回的Optional的供應(yīng)功能
* 返回值:返回一個(gè)Optional描述此的值Optional ,如果一個(gè)值存在,否則Optional所生產(chǎn)的供應(yīng)功能。
* 拋出:NullPointerException如果提供的函數(shù)為null或產(chǎn)生null結(jié)果
* @since 9
*/
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
Objects.requireNonNull(supplier);
if (isPresent()) {
return this;
} else {
@SuppressWarnings("unchecked")
Optional<T> r = (Optional<T>) supplier.get();
return Objects.requireNonNull(r);
}
}
/**
* 如果存在值,則返回僅包含該值的順序Stream ,否則返回空Stream 。
*
* 返回值:作為Stream的可選值
* @since 9
*/
public Stream<T> stream() {
if (!isPresent()) {
return Stream.empty();
} else {
return Stream.of(value);
}
}
/**
* 如果存在值,則返回該值,否則返回other 。
*
* 參數(shù):其他–要返回的值(如果不存在任何值)。 可以為null 。
* 返回值:值(如果存在),否則other
*/
public T orElse(T other) {
return value != null ? value : other;
}
/**
* 如果存在值,則返回該值,否則返回由供應(yīng)函數(shù)產(chǎn)生的結(jié)果。
*
* 參數(shù):供應(yīng)商–產(chǎn)生要返回的值的供應(yīng)函數(shù)
* 返回值:值(如果存在),否則提供功能產(chǎn)生的結(jié)果
*/
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
/**
* If a value is present, returns the value, otherwise throws
* {@code NoSuchElementException}.
*
* @return the non-{@code null} value described by this {@code Optional}
* @throws NoSuchElementException if no value is present
* @since 10
*/
public T orElseThrow() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
/**
* Optional中如果存在值,則返回該值,否則拋出由異常提供函數(shù)產(chǎn)生(Supplier接口實(shí)現(xiàn))的異常。
*
* 參數(shù):exceptionSupplier –產(chǎn)生要拋出的異常的提供函數(shù)
* 類型參數(shù):<X> –引發(fā)的異常類型
* 返回值:值(如果存在)
* 拋出:X –如果不存在任何值NullPointerException如果不存在任何值并且異常提供函數(shù)為null
* api注意:帶有空參數(shù)列表的對異常構(gòu)造函數(shù)的方法引用可用作提供者
*/
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
}
四、Optional 常用方法及使用示例
4.1 靜態(tài)方法 Optional.of()
- 方法作用: 為指定的值創(chuàng)建一個(gè)指定非 null 值的 Optional。
- 方法描述: of 方法通過工廠方法創(chuàng)建 Optional 實(shí)例,需要注意的是傳入的參數(shù)不能為 null,否則拋出 NullPointerException。
- 返回類型:Optional
-
示例代碼:
調(diào)用兩個(gè) Optional.of() 方法,一個(gè)傳入正常參數(shù),另一個(gè)傳入 null 參數(shù):
public static void main(String[] args) {
// 傳入正常值,正常返回一個(gè) Optional 對象
Optional<String> optional1 = Optional.of("mydlq");
// 傳入?yún)?shù)為 null,拋出 NullPointerException.
Optional optional2 = Optional.of(null);
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
Exception in thread "main" java.lang.NullPointerException
at java.util.Objects.requireNonNull(Objects.java:203)
at java.util.Optional.<init>(Optional.java:96)
at java.util.Optional.of(Optional.java:108)
at club.mydlq.OptionalExample.main(OptionalExample.java:12)
可以看到傳入正常參數(shù)正常返回 Optional 對象,傳入 null 參數(shù)返回 NullPointerException 異常。
4.2 靜態(tài)方法 Optional.ofNullable()
- 方法作用: 為指定的值創(chuàng)建一個(gè) Optional 對象,如果指定的參數(shù)為 null,不拋出異常,直接則返回一個(gè)空的 Optional 對象。
- 方法描述: ofNullable 方法是和 of 方式一樣,都是用于創(chuàng)建 Optional 對象,只是傳入的參數(shù) null 時(shí),會(huì)返回一個(gè)空的 Optional 對象,而不會(huì)拋出 NullPointerException 異常。
- 返回類型: Optional
-
示例代碼:
調(diào)用 Optional.ofNullable() 方法,傳入 null 參數(shù):
public static void main(String[] args) {
// 傳入正常值,正常返回一個(gè) Optional 對象
Optional<String> optional1 = Optional.ofNullable("mydlq");
// 傳入 null 參數(shù),正常返回 Optional 對象
Optional optional2 = Optional.ofNullable(null);
}
運(yùn)行代碼,可以觀察到正常傳入值和傳入 null 值時(shí),都沒有拋出異常。
4.3 對象方法 isPresent()
- 方法作用: 如果值存在則方法會(huì)返回 true,否則返回 false。
-
方法描述: 該方法其實(shí)就是用于判斷創(chuàng)建 Optional 時(shí)傳入?yún)?shù)的值是否為空,實(shí)現(xiàn)代碼就簡單一行,即
value != null所以如果不為空則返回 true,否則返回 false。 - 返回類型: boolean
- 示例代碼:
public static void main(String[] args) {
// 傳入正常值,正常返回一個(gè) Optional 對象,并使用 isPresent 方法
Optional optional1 = Optional.ofNullable("mydlq");
System.out.println("傳入正常值返回:" + optional1.isPresent());
// 傳入?yún)?shù)為 null 生成一個(gè) Optional 對象,并使用 isPresent 方法
Optional optional2 = Optional.ofNullable(null);
System.out.println("傳入 null 值返回:" + optional2.isPresent());
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
傳入正常值返回:true
傳入 null 值返回:false
可以看到傳入正常參數(shù)時(shí)調(diào)用 Optional 對象的 isPresent 方法時(shí)返回 true,傳入 null 參數(shù)返回 false。
4.4 對象方法 get()
- 方法作用: 如果 Optional 有值則將其返回,否則拋出 NoSuchElementException 異常。
- 方法描述: get 方法內(nèi)部實(shí)現(xiàn)其實(shí)就是判斷 Otpional 對象中的 value 屬性是否為 null,如果是就拋出 NoSuchElementException 異常,否則返回這個(gè) value 值。
- 返回類型: T
- 示例代碼:
public static void main(String[] args) {
// 傳入正常值,正常返回一個(gè) Optional 對象,并使用 get 方法獲取值
Optional optional1 = Optional.ofNullable("mydlq");
System.out.println(optional1.get());
// 傳入?yún)?shù)為 null 生成一個(gè) Optional 對象,并使用 get 方法獲取值
Optional optional2 = Optional.ofNullable(null);
System.out.println(optional2.get());
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
傳入正常參數(shù):mydlq
Exception in thread "main" java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:135)
at club.mydlq.OptionalExample.main(OptionalExample.java:14)
BASH可以觀察到傳入正常值的 Optional 調(diào)用 get 方法正常輸出值,通過空的 optional 對象使用 get 方法獲取值時(shí),拋出 NoSuchElementException 異常。
4.5 對象方法 ifPresent()
- 方法作用: 如果值存在則使用該值調(diào)用 consumer , 否則不做任何事情。
- 方法描述: 該方法 ifPresent(Consumer<? super T> consumer) 中參數(shù)接收的是 Consumer 類,它包含一個(gè)接口方法 accept(),該方法能夠?qū)魅氲闹颠M(jìn)行處理,但不會(huì)返回結(jié)果。這里傳入?yún)?shù)可以傳入 Lamdda 表達(dá)式或 Consumer 對象及實(shí)現(xiàn) Consumer 接口的類的對象。
- 返回類型: void
- 示例代碼:
public static void main(String[] args) {
// 創(chuàng)建 Optional 對象,然后調(diào)用 Optional 對象的 ifPresent 方法,傳入 Lambda 表達(dá)式
Optional optional1 = Optional.ofNullable("mydlq1");
optional1.ifPresent((value) -> System.out.println("Optional 的值為:" + value));
// 創(chuàng)建 Optional 對象,調(diào)用 Optional 對象的 ifPresent 方法,傳入實(shí)現(xiàn) Consumer 匿名內(nèi)部類
Optional optional2 = Optional.ofNullable("mydlq2");
Consumer<String> consumer = new Consumer() {
@Override
public void accept(Object value) {
System.out.println("Optional 的值為:" + value);
}
};
optional2.ifPresent(consumer);
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
Optional 的值為:mydlq1
Optional 的值為:mydlq2
可以觀察到,調(diào)用 ifPresent 使用 lambda 或者內(nèi)部匿名類方法,都是為了再執(zhí)行 Optional 對象的 ifPresent 方法時(shí),執(zhí)行一段代碼邏輯。
4.6 對象方法 orElse()
- 方法作用: 如果該值存在就直接返回, 否則返回指定的其它值。
-
方法描述: orElse 方法實(shí)現(xiàn)很簡單,就是使用三目表達(dá)式對傳入的參數(shù)值進(jìn)行 null 驗(yàn)證,即
value != null ? value : other;如果為 null 則返回 true,否則返回 false。 - 返回類型: T
- 示例代碼:
public static void main(String[] args) {
// 傳入正常參數(shù),獲取一個(gè) Optional 對象,并使用 orElse 方法設(shè)置默認(rèn)值
Optional optional1 = Optional.ofNullable("mydlq");
Object object1 = optional1.orElse("默認(rèn)值");
System.out.println("如果值不為空:"+object1);
// 傳入 null 參數(shù),獲取一個(gè) Optional 對象,并使用 orElse 方法設(shè)置默認(rèn)值
Optional optional2 = Optional.ofNullable(null);
Object object2 = optional2.orElse("默認(rèn)值");
System.out.println("如果值為空:"+object2);
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
如果值不為空:mydlq
如果值為空:默認(rèn)值
可以觀察到,如果 Optional 的值為空,則返回 orElse() 方法設(shè)置的默認(rèn)值,否則返回 Optional 中的值。
4.7、對象方法 orElseGet()
- 方法作用: 如果該值存在就返回值,否則觸發(fā) other,并返回 other 調(diào)用的結(jié)果。
- 方法描述: orElseGet 方法和 orElse 方法類似,都是在 Optional 值為空時(shí),返回一個(gè)默認(rèn)操作,只不過 orElse 返回的是默認(rèn)值,而 orElseGet 是執(zhí)行 lambda 表達(dá)式,然后返回 lambda 表達(dá)式執(zhí)行后的結(jié)果。
- 返回類型: T
- 示例代碼:
public static void main(String[] args) {
// 傳入正常參數(shù),獲取一個(gè) Optional 對象,并使用 orElse 方法設(shè)置默認(rèn)值
Optional optional1 = Optional.ofNullable("mydlq");
Object object1 = optional1.orElseGet(() -> {
String defaultVal = "執(zhí)行邏輯和生成的默認(rèn)值";
return defaultVal;
});
System.out.println("輸出的值為:"+object1);
// 傳入 null 參數(shù),獲取一個(gè) Optional 對象,并使用 orElse 方法設(shè)置默認(rèn)值
Optional optional2 = Optional.ofNullable(null);
Object object2 = optional2.orElseGet(() -> {
String defaultVal = "執(zhí)行邏輯和生成的默認(rèn)值";
return defaultVal;
});
System.out.println("輸出的值為:"+object2);
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
輸出的值為:mydlq
輸出的值為:執(zhí)行邏輯和生成的默認(rèn)值
可也觀察到,當(dāng) Optional 值為不為空時(shí)正常返回帶值的 Optional,如果 Optional 為空則返回 orElseGet 方法中 lambda 表達(dá)式執(zhí)行后生成的值。
4.8、對象方法 orElseThrow()
- 方法作用: 如果 Optional 存在該值,返回包含的值,否則拋出由 Supplier 繼承的異常。
- 方法描述: orElseThrow 方法其實(shí)就是判斷創(chuàng)建 Optional 時(shí)傳入的參數(shù)是否為 null,如果是非 null 則返回傳入的值,否則拋出 異常。
- 返回類型: T
- 示例代碼:
public static void main(String[] args) {
// 傳入正常參數(shù),獲取一個(gè) Optional 對象,并使用 orElseThrow 方法
try {
Optional optional1 = Optional.ofNullable("mydlq");
Object object1 = optional1.orElseThrow(() -> {
System.out.println("執(zhí)行邏輯,然后拋出異常");
return new RuntimeException("拋出異常");
}
);
System.out.println("輸出的值為:" + object1);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
// 傳入 null 參數(shù),獲取一個(gè) Optional 對象,并使用 orElseThrow 方法
try {
Optional optional2 = Optional.ofNullable(null);
Object object2 = optional2.orElseThrow(() -> {
System.out.println("執(zhí)行邏輯,然后拋出異常");
return new RuntimeException("拋出異常");
}
);
System.out.println("輸出的值為:" + object2);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
值為不為空輸出的值:mydlq
執(zhí)行邏輯,然后拋出異常
java.lang.RuntimeException: 拋出異常
at club.mydlq.OptionalExample.lambda$main$1(OptionalExample.java:25)
at java.util.Optional.orElseThrow(Optional.java:290)
at club.mydlq.OptionalExample.main(OptionalExample.java:23)
可以觀察到,當(dāng)創(chuàng)建 Optional 時(shí)如果傳入的參數(shù)為空則執(zhí)行 Lambda 表達(dá)式代碼邏輯后拋出異常信息,否則返回傳入的參數(shù)值。
4.9、對象方法 map()
- 方法作用: 如果有值,則對其執(zhí)行調(diào)用映射函數(shù)得到返回值。如果返回值不為 null,則創(chuàng)建包含映射返回值的 Optional 作為 map 方法返回值,否則返回空 Optional。
- 方法描述: map 方法主要用于獲取某個(gè)對象中的某個(gè)屬性值的 Optional 對象時(shí)使用。map 方法調(diào)用時(shí),首先驗(yàn)證傳入的映射函數(shù)是否為空,如果為空則拋出異常。然后,再檢測 Optional 的 value 是否為空,如果是,則返回一個(gè)空 value 的 Optional 對象。如果傳入的映射函數(shù)和 Optinal 的 value 都不為空,則返回一個(gè)帶 value 對象屬性的 Optional 對象。
- 返回類型: Optional
- 示例代碼:
示例1:創(chuàng)建 Map 集合,存儲(chǔ)一些鍵值對信息,通過 Optional 操作 Map 獲取值,然后觀察:
public static void main(String[] args) {
// 創(chuàng)建 map 對象
Map<String, String> userMap = new HashMap<>();
userMap.put("name1", "mydlq");
userMap.put("name2", null);
// 傳入 Map 對象參數(shù),獲取一個(gè) Optional 對象,獲取 name1 屬性
Optional<String> optional1 = Optional.of(userMap).map(value -> value.get("name1"));
// 傳入 Map 對象參數(shù),獲取一個(gè) Optional 對象,獲取 name2 屬性
Optional<String> optional2 = Optional.of(userMap).map(value -> value.get("name2"));
// 獲取 Optional 的值
System.out.println("獲取的 name1 的值:" + optional1.orElse("默認(rèn)值"));
System.out.println("獲取的 name2 的值:" + optional2.orElse("默認(rèn)值"));
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
獲取的 Optional 的值:mydlq
獲取的 Optional 的值:默認(rèn)值
示例2:創(chuàng)建一個(gè)用戶類,使用 Optional 操作用戶對象,獲取其 name 參數(shù),結(jié)合 Optional 的 map 方法獲取值,進(jìn)行觀察:
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
使用 Optional 的 map 方法對值處理:
public static void main(String[] args) {
// 創(chuàng)建一個(gè)對象,設(shè)置姓名屬性而不設(shè)置性別,這時(shí)候性別為 null
User user1 = new User("測試名稱");
User user2 = new User();
// 使用 Optional 存儲(chǔ) User 對象
Optional<User> optional1 = Optional.ofNullable(user1);
Optional<User> optional2 = Optional.ofNullable(user2);
// 獲取對象的 name 屬性值
String name1 = optional1.map(User::getName).orElse("未填寫");
String name2 = optional2.map(User::getName).orElse("未填寫");
// 輸出結(jié)果
System.out.println("獲取的名稱:" + name1);
System.out.println("獲取的名稱:" + name2);
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
獲取的名稱:測試名稱
獲取的名稱:未填寫
通過上面兩個(gè)示例觀察到,通過 Optional 對象的 map 方法能夠獲取映射對象中的屬性,創(chuàng)建 Optional 對象,并以此屬性充當(dāng) Optional 的值,結(jié)合 orElse 方法,如果獲取的屬性的值為空,則設(shè)置個(gè)默認(rèn)值。
4.10 對象方法 flatMap()
- 方法作用: 如果值存在,返回基于 Optional 包含的映射方法的值,否則返回一個(gè)空的 Optional。
- 方法描述: flatMap 方法和 map 方法類似,唯一的不同點(diǎn)就是 map 方法會(huì)對返回的值進(jìn)行 Optional 封裝,而 flatMap 不會(huì),它需要手動(dòng)執(zhí)行 Optional.of 或 Optional.ofNullable 方法對 Optional 值進(jìn)行封裝。
- 返回類型: Optional
- 示例代碼:
public static void main(String[] args) {
// 創(chuàng)建 map 對象
Map<String, String> userMap = new HashMap<>();
userMap.put("name", "mydlq");
userMap.put("sex", "男");
// 傳入 Map 對象參數(shù),獲取一個(gè) Optional 對象
Optional<Map<String, String>> optional1 = Optional.of(userMap);
// 使用 Optional 的 flatMap 方法,獲取 Map 中的 name 屬性
// 然后通過獲取的值手動(dòng)創(chuàng)建一個(gè)新的 Optional 對象
Optional optional2 = optional1.flatMap(value -> Optional.ofNullable(value.get("name")));
// 獲取 Optional 的 value
System.out.println("獲取的 Optional 的值:" + optional2.get());
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
獲取的 Optional 的值:mydlq
根據(jù)結(jié)果觀察,可以看到 flatMap 和 map 方法沒有什么區(qū)別,但是仔細(xì)看,代碼中調(diào)用 flatMap 后,需要手動(dòng)執(zhí)行 of 或 ofNullable 方法創(chuàng)建了 Optional 對象。
4.11 對象方法 filter()
- 方法作用: 如果有值并且滿足斷言條件返回包含該值的 Optional,否則返回空 Optional。
- 方法描述: filter 方法通過傳入的限定條件對 Optional 實(shí)例的值進(jìn)行過濾,如果 Optional 值不為空且滿足限定條件就返回包含值的 Optional,否則返回空的 Optional。這里設(shè)置的限定條件需要使用實(shí)現(xiàn)了 Predicate 接口的 lambda 表達(dá)式來進(jìn)行配置。
- 返回類型: Optional
- 示例代碼:
public static void main(String[] args) {
// 創(chuàng)建一個(gè)測試的 Optional 對象
Optional<String> optional = Optional.ofNullable("mydlq");
// 調(diào)用 Optional 的 filter 方法,設(shè)置一個(gè)滿足的條件,然后觀察獲取的 Optional 對象值是否為空
Optional optional1 =optional.filter((value) -> value.length() > 2);
System.out.println("Optional 的值不為空::" + optional.isPresent());
// 調(diào)用 Optional 的 filter 方法,設(shè)置一個(gè)不滿足的條件,然后觀察獲取的 Optional 對象值是否為空
Optional optional2 =optional.filter((value) -> value.length() <2);
System.out.println("Optional 的值不為空::" + optional2.isPresent());
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
Optional 的值不為空:true
Optional 的值不為空:false
根據(jù)結(jié)果可以觀察到,可以通過 filter 設(shè)置一個(gè)條件來判斷 Optional 的值,如果滿足條件就返回帶值的 Optional,否則返回空的 Optional。
4.12 Optional 常用示例組合
Optional 類(java.util.Optional) 是一個(gè)容器類,它可用保存類型的 T 的值,即使 T 為 null 也可以使用 Optional 存儲(chǔ),這樣我就不用顯示進(jìn)行空值檢測,防止空指針異常。
上面也介紹了 Optional 的各種方法,在實(shí)際使用中這些方法常常組合使用。且很多方法也常與 Lambda 表達(dá)式結(jié)合,獲取我們想要的結(jié)果的值。
下面是常用的示例,可以作為參考:
對集合中的對象屬性進(jìn)行過濾
創(chuàng)建一個(gè) User 對象實(shí)體類,里面包含 name 屬性:
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
創(chuàng)建一個(gè)使用 main 方法的類,創(chuàng)建幾個(gè) User 對象且設(shè)置不同的值,有的對象為 null 有的屬性不設(shè)置,然后通過 Optional 獲取 name 屬性值加入集合,進(jìn)行測試:
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class OptionalExample {
/**
* 測試的 main 方法
*/
public static void main(String[] args) {
// 創(chuàng)建一個(gè)測試的用戶集合
List<User> userList = new ArrayList<>();
// 創(chuàng)建幾個(gè)測試用戶
User user1 = new User("abc");
User user2 = new User("efg");
User user3 = null;
// 將用戶加入集合
userList.add(user1);
userList.add(user2);
userList.add(user3);
// 創(chuàng)建用于存儲(chǔ)姓名的集合
List<String> nameList = new ArrayList();
// 循環(huán)用戶列表獲取用戶信息,值獲取不為空且用戶以 a 開頭的姓名,
// 如果不符合條件就設(shè)置默認(rèn)值,最后將符合條件的用戶姓名加入姓名集合
for (User user : userList) {
nameList.add(Optional.ofNullable(user).map(User::getName).filter(value -> value.startsWith("a")).orElse("未填寫"));
}
// 輸出名字集合中的值
System.out.println("通過 Optional 過濾的集合輸出:");
nameList.stream().forEach(System.out::println);
}
}
輸出運(yùn)行結(jié)果:
通過 Optional 過濾的集合輸出:
abc
未填寫
未填寫
通過上面,可以觀察到,使用 Optional 有時(shí)候可以很方便的過濾一些屬性,而且它的方法可以通過鏈?zhǔn)秸{(diào)用,方法間相互組合使用,使我們用少量的代碼就能完成復(fù)雜的邏輯。
map經(jīng)典判空之嵌套if
判斷map不為空,map中的key-value不為null且不為空白字符串,常規(guī)玩法要么是一組嵌套if,要是是一個(gè)tay-catch。
public static void main(String[] args) {
System.out.println(test1());
System.out.println(test2());
System.out.println(test3());
System.out.println(test4());
}
public static String test1() {
//假裝外部傳入不可控map一個(gè),比如sevlet接受前端傳參
Map pm = new HashMap();
pm.put("key1", "value1");
Optional<Map> mapOptional = Optional.ofNullable(pm);
return mapOptional.map(map -> map.get("key1"))
.filter(value -> !"".equals(value))
.flatMap(value -> {
//一大堆業(yè)務(wù)處理...
return Optional.ofNullable("test1成功執(zhí)行");
}).orElse("test1停車了");
}
public static String test2() {
//假裝外部傳入不可控map一個(gè),比如sevlet接受前端傳參
Map pm = new HashMap();
pm.put("key1", "");
Optional<Map> mapOptional = Optional.ofNullable(pm);
return mapOptional.map(map -> map.get("key1"))
.filter(value -> !"".equals(value))
.flatMap(value -> {
//一大堆業(yè)務(wù)處理...
return Optional.ofNullable("test2成功執(zhí)行");
}).orElse("test2停車了");
}
public static String test3() {
//假裝外部傳入不可控map一個(gè),比如sevlet接受前端傳參
Map pm = new HashMap();
pm.put("key1", null);
Optional<Map> mapOptional = Optional.ofNullable(pm);
return mapOptional.map(map -> map.get("key1"))
.filter(value -> !"".equals(value))
.flatMap(value -> {
//一大堆業(yè)務(wù)處理...
return Optional.ofNullable("test3成功執(zhí)行");
}).orElse("test3停車了");
}
public static String test4() {
//假裝外部傳入map一個(gè),不傳指定key
Map pm = new HashMap();
Optional<Map> mapOptional = Optional.ofNullable(pm);
return mapOptional.map(map -> map.get("key1"))
.filter(value -> !"".equals(value))
.flatMap(value -> {
//開始啪啪業(yè)務(wù)邏輯 發(fā)短信啊crud啊...
return Optional.ofNullable("test4成功執(zhí)行");
}).orElse("test4停車了");
}
輸出運(yùn)行結(jié)果:
test1成功執(zhí)行
test2停車了
test3停車了
test4停車了
總結(jié)一下:

五、Java 9 增強(qiáng)
上面介紹了 Java 8 的特性,Java 9 為 Optional 類添加了三個(gè)方法:or()、ifPresentOrElse() 和 stream()。
5.1 or() 方法
or()函數(shù)源碼如下:
/**
* 如果值存在時(shí),返回一個(gè)Optional描述的值,否則將返回一個(gè)Optional產(chǎn)生通過供給功能。
*
* 參數(shù):供應(yīng)商–產(chǎn)生要返回的Optional的供應(yīng)功能
* 返回值:返回一個(gè)Optional描述此的值Optional ,如果一個(gè)值存在,否則Optional所生產(chǎn)的供應(yīng)功能。
* 拋出:NullPointerException如果提供的函數(shù)為null或產(chǎn)生null結(jié)果
* @since 9
*/
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
Objects.requireNonNull(supplier);
if (isPresent()) {
return this;
} else {
@SuppressWarnings("unchecked")
Optional<T> r = (Optional<T>) supplier.get();
return Objects.requireNonNull(r);
}
}
or() 方法與 orElse() 和 orElseGet() 類似,它們都在對象為空的時(shí)候提供了替代情況。or() 的返回值是由 Supplier 參數(shù)產(chǎn)生的另一個(gè) Optional 對象。
如果對象包含值,則 Lambda 表達(dá)式不會(huì)執(zhí)行:
public void whenEmptyOptional_thenGetValueFromOr() {
User result = Optional.ofNullable(user)
.or( () -> Optional.of(new User("default","1234"))).get();
assertEquals(result.getEmail(), "default");
}
上面的示例中,如果 user 變量是 null,它會(huì)返回一個(gè) Optional,它所包含的 User 對象,其電子郵件為 “default”。
5.2 ifPresentOrElse() 方法
ifPresentOrElse() 方法需要兩個(gè)參數(shù):一個(gè) Consumer 和一個(gè) Runnable。如果對象包含值,會(huì)執(zhí)行 Consumer 的動(dòng)作,否則運(yùn)行 Runnable。源碼如下:
/**
* 如果存在值,則使用該值執(zhí)行給定的操作,否則執(zhí)行給定的基于空的操作。
* 參數(shù):動(dòng)作–要執(zhí)行的動(dòng)作(如果存在值)emptyAction –要執(zhí)行的基于空的操作(如果不存在任何值)
* 拋出:NullPointerException如果存在一個(gè)值并且給定的操作為null ,或者不存在任何值并且給定的基于空的操作為null
* @since 9
*/
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
if (value != null) {
action.accept(value);
} else {
emptyAction.run();
}
}
如果你想在有值的時(shí)候執(zhí)行某個(gè)動(dòng)作,或者只是跟蹤是否定義了某個(gè)值,那么這個(gè)方法非常有用:
Optional.ofNullable(user).ifPresentOrElse( u -> logger.info("User is:" + u.getEmail()),() -> logger.info("User not found"));
5.3 stream()
最后介紹的是新的 stream() 方法,它通過把實(shí)例轉(zhuǎn)換為 Stream 對象,讓你從廣大的 Stream API 中受益。如果沒有值,它會(huì)得到空的 Stream;有值的情況下,Stream 則會(huì)包含單一值。源碼如下:
/**
* 如果存在值,則返回僅包含該值的順序Stream ,否則返回空Stream 。
*
* 返回值:作為Stream的可選值
* @since 9
*/
public Stream<T> stream() {
if (!isPresent()) {
return Stream.empty();
} else {
return Stream.of(value);
}
}
我們來看一個(gè)把 Optional 處理成 Stream 的例子:
public void whenGetStream_thenOk() {
User user = new User("john@gmail.com", "1234");
List<String> emails = Optional.ofNullable(user)
.stream()
.filter(u -> u.getEmail() != null && u.getEmail().contains("@"))
.map( u -> u.getEmail())
.collect(Collectors.toList());
assertTrue(emails.size() == 1);
assertEquals(emails.get(0), user.getEmail());
}
這里對 Stream 的使用帶來了其 filter()、map() 和 collect() 接口,以獲取 List。
Optional做為空判斷時(shí),注意orElse和orElseGet使用區(qū)別
- 使用 Optional.ofNullable(obj).orElse 時(shí),無論 obj 是否為 null,都會(huì)執(zhí)行 orElse 的方法。
- 使用 Optional.ofNullable(obj).orElseGet 時(shí),只有 obj 是否為 null,才會(huì)執(zhí)行 orElseGet 里的方法。
- 傳入Optonal值為非空,orElse或orElseGet都會(huì)執(zhí)行,返回傳入值。
- 傳入Optional值為空,orElse會(huì)執(zhí)行,orElseGet不會(huì)執(zhí)行,返回執(zhí)行方法體的結(jié)果。
- 傳入Optonal值非空,返回本身。
- 傳入Optional值為空,返回other。
- 由于orElseGet入?yún)⑹褂玫氖荢upplier(類似懶加載),所以在只有在傳入Optional值為空的時(shí)候,才會(huì)去執(zhí)行。
- 對于orElseGet:返回值(如果存在),否則調(diào)用{other}并返回該調(diào)用的結(jié)果。
- 對于orElse來說,無論傳入Optional值是否為空,都會(huì)執(zhí)行。
- 對于orElse:返回值(如果存在),否則返回{other}。
- 對于性能要求比較高的場景,建議使用orElseGet。
參考:
https://www.aqwdzy.com/content/84
https://blog.csdn.net/weixin_45821811/article/details/115656637
https://blog.csdn.net/weixin_43888891/article/details/124788806