一、摘要
NullPointerException,中文名: 空指針異常 ,也簡稱 NPE,是軟件系統(tǒng)中最常見的錯誤異常之一。
很久以前 Google Guava 項目引入了Optional
作為解決空指針異常的一種方式,不贊成寫過多的代碼來顯式檢查null
,以期望程序員寫出整潔同時可讀性更高的代碼。
受 Google Guava 的影響,Optional 現(xiàn)在也成為了Java 8 及以上庫代碼的一部分。
在介紹Optional
技術(shù)之前,我們不禁會發(fā)出一個疑問:為什么谷歌不贊成寫過多的代碼來顯式檢查null
?
下面是某個常見的參數(shù)判空代碼,樣例如下。
// 判斷行政區(qū)是否為空
if(country != null){
// 判斷行政區(qū)的上一級,行政城市是否為空
if(country.getCity() != null){
// 判斷行政城市的上一級,行政省是否為空
if(country.getCity().getProvince() != null){
// 獲取對應(yīng)的行政省相關(guān)的數(shù)據(jù)
return country.getCity().getProvince().getName();
}
}
}
這還是最普通的三層判斷,假如有很大一段業(yè)務(wù)邏輯處理的時候,你會發(fā)現(xiàn)代碼不光看起來很臃腫,并且難以閱讀,可讀性很差!
如果調(diào)整為使用Optional
來編寫的話,可以轉(zhuǎn)換成如下寫法:
// 獲取當(dāng)前行政區(qū)最頂級的省信息名稱
String result = Optional.ofNullable(country)
.map(Country::getCity)
.map(City::getProvince)
.map(Province::getName)
.orElse("error");
采用Optional
來編程之后,整個代碼的可讀性和整潔度,是不是要干凈很多!
這也是為什么推薦大家使用Optional
的原因啦!
當(dāng)然廢話也不多說,代碼直接擼起來!
二、案例實踐
在 JDK8 中,Optional 共有 12 個核心方法,下面我們一起來看看他們的用法!
2.1、empty()
empty 方法返回一個不包含值的 Optional 實例,單獨使用沒什么意義,主要和其他方法搭配使用。
Optional optional = Optional.empty();
System.out.println(optional);
-- 輸出結(jié)果
Optional.empty
2.2、of()
of 方法會返回一個 Optional 實例,如果傳入的值非空,會返回包含指定值的對象;如果傳入空,會立刻拋出空指針異常。
// 非空情況下,會正常返回
Optional optional = Optional.of("hello world");
System.out.println(optional);
-- 輸出結(jié)果
Optional[hello world]
// 為空情況下,會拋空指針異常
Optional optional = Optional.of(null);
System.out.println(optional);
-- 輸出結(jié)果
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)
2.3、ofNullable()
ofNullable 方法會返回一個 Optional 實例,如果傳入的值非空,會返回包含指定值的對象;如果傳入空,會返回不包含任何值的 empty 對象,也就是最開始介紹的Optional.empty()
對象。
// 非空情況下,會正常返回
Optional optional = Optional.ofNullable("hello world");
System.out.println(optional);
-- 輸出結(jié)果
Optional[hello world]
// 為空情況下,會返回 empty 對象
Optional optional = Optional.ofNullable(null);
System.out.println(optional);
-- 輸出結(jié)果
Optional.empty
2.4、isPresent()
isPresent 方法用來判斷實例是否包含值,如果包含非空值,返回 true,否則返回 false。
// 非空值,返回true
boolean rs1 = Optional.ofNullable("hello").isPresent();
System.out.println(rs1);
// 空值,返回false
boolean rs2 = Optional.ofNullable(null).isPresent();
System.out.println(rs2);
-- 輸出結(jié)果
true
false
2.5、get()
get 方法,如果實例包含非空值,則返回當(dāng)前值;否則拋出 NoSushElementException 異常。
// 非空值,返回當(dāng)前值
Object rs = Optional.ofNullable("hello world").get();
System.out.println(rs);
-- 輸出結(jié)果
hello world
// 空值,會拋出 NoSushElementException 異常
Object rs = Optional.ofNullable(null).get();
System.out.println(rs);
-- 輸出結(jié)果
Exception in thread "main" java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:135)
2.6、ifPresent()
ifPresent 方法作用是當(dāng)實例包含非空值時,執(zhí)行傳入的 Consumer,比如調(diào)用一些其他方法;如果包含的值為空,不執(zhí)行任何操作。
Optional.ofNullable("hello world")
.ifPresent( x - > {
System.out.println(x);
});
-- 輸出結(jié)果
hello world
2.7、filter()
filter 方法用于過濾不符合條件的值,接收一個Predicate
參數(shù),如果符合條件,會返回當(dāng)前的Optional
實例,否則返回 empty 實例。
Optional.ofNullable("hello world")
.filter(x - > x.contains("hello"))
.ifPresent(x - > {
System.out.println(x);
});
-- 輸出結(jié)果
hello world
2.8、map()
map 方法是鏈?zhǔn)秸{(diào)用避免空指針的核心方法,當(dāng)實例包含值時,對值執(zhí)行傳入的Function
函數(shù)接口方法,并返回一個代表結(jié)果值新的Optional
實例,也就是將返回的結(jié)果再次包裝成Optional
對象。
Optional.ofNullable("hello+world")
.map(t - > {
if(t.contains("+")){
return t.replace("+", " ");
}
return t;
}).ifPresent(t - > {
System.out.println(t);
});
-- 輸出結(jié)果
hello world
2.9、flatMap()
flatMap 方法與 map 方法類似,唯一不同的地方在于: 需要手動將返回的值,包裝成Optional
實例,并且參數(shù)值不允許為空 。
Optional.ofNullable("hello+world")
.flatMap(t - > {
if(t.contains("+")){
t = t.replace("+", " ");
}
// 不同之處
return Optional.of(t);
}).ifPresent(t - > {
System.out.println(t);
});
-- 輸出結(jié)果
hello world
2.10、orElse()
orElse 方法作用是如果實例包含非空值,那么返回當(dāng)前值;否則返回指定的默認(rèn)值。
Object rs = Optional.ofNullable(null).orElse("null");
System.out.println(rs);
-- 輸出結(jié)果
null
2.11、orElseGet()
orElseGet 方法作用是如果實例包含非空值,返回這個值;否則,它會執(zhí)行作為參數(shù)傳入的Supplier
函數(shù)式接口方法,并返回其執(zhí)行結(jié)果。
Object result = Optional.ofNullable(null)
.orElseGet(() - > {
return "error";
});
System.out.println(result);
-- 輸出結(jié)果
error
2.12、orElseThrow()
orElseThrow 方法作用是如果實例包含非空值,返回這個值;否則,它會執(zhí)行作為參數(shù)傳入的異常類。
Optional.ofNullable(null)
.orElseThrow(() - > new RuntimeException("參數(shù)為空"));
-- 輸出結(jié)果
Exception in thread "main" java.lang.RuntimeException: 參數(shù)為空
at com.x.x.x.x.OptionalTest.lambda$main$10(OptionalTest3.java:144)
at java.util.Optional.orElseThrow(Optional.java:290)
三、小結(jié)
以上就是 JDK8 新增的Optional
類的常用方法總結(jié),其中ofNullable
、map
和orElse
方法搭配使用的最多。
另外orElse
、orElseGet
、orElseThrow
區(qū)別如下:
orElse
:如果實例包含空值,返回傳入指定的值orElseGet
:如果實例包含空值,返回傳入的方法中返回值orElseThrow
:如果實例包含空值,返回指定的異常類型
在實際使用的時候,還得結(jié)合具體的場景進行合理選擇,有時候并不是全部采用Optional
來解決NPE
異常代碼才更加優(yōu)雅,比如當(dāng)前對象比較簡單,就是一個簡單判斷,通過obj != null
足以解決問題。
因此在保證業(yè)務(wù)功能的正確和穩(wěn)定性的基礎(chǔ)之上,適當(dāng)?shù)倪x擇相關(guān)的工具來優(yōu)化代碼的整潔度和可讀性,更能發(fā)揮出錦上添花的效果!
-
程序
+關(guān)注
關(guān)注
117文章
3832瀏覽量
84353 -
代碼
+關(guān)注
關(guān)注
30文章
4922瀏覽量
72228 -
軟件系統(tǒng)
+關(guān)注
關(guān)注
0文章
68瀏覽量
9743 -
jdk8
+關(guān)注
關(guān)注
0文章
4瀏覽量
2022
發(fā)布評論請先 登錄
JDK動態(tài)代理的原理
樹莓派安裝JDK
畢昇JDK 8 Dynamic CDS 特性介紹
JDK8 Optional類新特性
Java數(shù)組的常用方法_Java:數(shù)組工具類Arrays類的常用方法的用法及代碼
如何解決JDK8小版本升級后性能下降的問題

畢昇JDK8和JDK11首次同時發(fā)布兩個版本

JAVA8提供了Optional類來優(yōu)化這種寫法
JDK8 Stream數(shù)據(jù)流效率分析
基于JDK 1.8來分析Thread類的源碼
Java中Arrays類是什么 Arrays常用方法

JDK中java.lang.Arrays 類的源碼解析

JDK11升級JDK17最全實踐干貨來了

JDK8升級JDK11最全實踐干貨來了

評論