Java8新特性系列我們已經介紹了Stream、Lambda表達式、DateTime日期時間處理,最後以“NullPointerException” 的克星Optional類的講解來收尾。
背景
作爲開發人員每天與NullPointerException鬥智鬥勇。每接收到參數或調用方法獲得值得判斷一下是否爲null。稍不留意,空指針異常就像幽靈一樣出現了。
這篇文章我們來學習Java8是如何通過Optional類來避免空指針異常的。
先來看一下不使用Optional類時,我們爲了防止NullPointerException會怎麽處理。
爲了防止出現異常,需要不停的判斷對象是否爲null。但如果業務邏輯比較複雜,會湧現出大量的ifelse。看似邏輯缜密,但易讀性卻並不高。
爲了解決相關問題,在Effective Java中建議若方法返回類型爲集合,則通過返回空集合以避免 NullPointerException,真是煞費苦心。
先看一下上面的代碼使用Optional之後會變成什麽樣子。
對照一下代碼,看看神不神奇?!
Optional類簡介
java.util.Optional類的引入很好的解決空指針異常,類聲明如下:
java.util.Optional類是一個封裝了Optional值的容器對象,Optional值可以爲null,如果值存在,調用isPresent()方法返回true,調用get()方法可以獲取值。
通過源代碼會發現,它並沒有實現java.io.Serializable接口,因此應避免在類屬性中使用,防止意想不到的問題。
除了Optional類之外,還擴展了一些常用類型的Optional對象,比如:OptionalDouble、OptionalInt、OptionalLong。用法基本上相似。
下面通過具體的操作和功能來了解Optional類。
創建Optional對象
創建Optional對象有三種方法:empty()、of()、ofNullable(),均爲靜態方法。
如果Optional對象沒有值則用empty()方法。
如果確定Optional對象的值不爲null,則可用of()方法。
如果不確定Optional對象的值是否爲null,則可用ofNullable()。比如上面,不確定Person對象是不否null,就用了ofNullable()方法。當然,也可以直接給該方法傳null。
此時,通過調用其isPresent方法可以查看該Optional中是否值爲null。
此時如果直接調用get方法獲取值,則會抛出異常。
get獲取Optional中的值
通過get方法可獲取Optional中的值,但如果值爲null,則會抛出異常。
異常信息:
此時,需要另外一個方法的輔助:isPresent()。該方法可判定Optional中是否有值,如果有則返回true,如果沒有則返回false。
map獲取Optional中的值
對于對象操作,也可以通過map來獲取值,最開始簡化的例子就是如此。
map方法,如果有值,則對其執行調用映射函數得到返回值。如果返回值不爲null,則創建包含映射返回值的Optional作爲map方法返回值,否則返回空Optional。
flatMap獲取Optional中的值
如果有值,則返回Optional類型返回值,否則返回空Optional。flatMap與map方法類似。但flatMap中的mapper返回值必須是Optional。調用結束時,flatMap不會對結果用Optional封裝。
調用的是當前類OptionalTest的另外一個方法:
orElse獲取Optional中的值
orElse方法,如果有值就返回,否則返回一個給定的值作爲默認值;
上面這種情況就會返回“–”。
在此,這種操作與三目運算效果一樣。
orElseGet獲取Optional中的值
orElseGet()方法與orElse()方法作用類似,但生成默認值的方式不同。該方法接受一個Supplier函數式接口參數,用于生成默認值;
很顯然,這裏可以處理更多的業務邏輯。
orElseThrow獲取Optional中的值
orElseThrow()方法與get()方法類似,當值爲null時調用會抛出NullPointerException異常,但該方法可以指定抛出的異常類型。
此時打印異常信息爲:
判斷並執行操作
ifPresent方法,可對值進行判斷然後打印,接收參數爲Consumer函數式接口。
當然,也可以在函數中執行其他複雜操作:
filter()方法過濾
filter()方法可用于判斷Optional對象是否滿足給定條件,一般用于條件過濾:
使用誤區
關于使用Optional的誤區有以下:
- 正確的使用創建方法,不確定是否爲null時盡量選擇ofNullable方法。
- 避免用在成員變量上(原因上面已經提到);
- 避免直接調用Optional對象的get和isPresent方法;
最後一條可能難理解,試想一下如果先用isPresent方法獲得是否存在,然後決定是否調用get方法和之前的ifelse判斷並無二致。
Java8提倡函數式編程,新增的許多API都可以用函數式編程表示,Optional類也是其中之一。
作者:secbro2 來源:掘金 商業用途請與原作者聯系,本文只做展示分享,不妥侵刪!