Java8新特性 Optional类
作為開發人員每天與NullPointerException斗智斗勇。每接收到參數或調用方法獲得值得判斷一下是否為null。稍不留意,空指針異常就像幽靈一樣出現了。這篇文章我們來學習Java8是如何通過Optional類來避免空指針異常的。
先來看一下不使用Optional類時,我們為了防止NullPointerException會怎么處理。重要的一點是 Optional 不是 Serializable。因此,它不應該用作類的字段
為了防止出現異常,需要不停的判斷對象是否為null。但如果業務邏輯比較復雜,會涌現出大量的ifelse。看似邏輯縝密,但易讀性卻并不高。為了解決相關問題,在Effective Java中建議若方法返回類型為集合,則通過返回空集合以避免 NullPointerException,真是煞費苦心。先看一下上面的代碼使用Optional之后會變成什么樣子。
public String getParentNameWithOptional(Person son) {return Optional.ofNullable(son).map(Person::getParent).map(Person::getUsername).orElse("--"); }一、Optional類簡介
java.util.Optional類的引入很好的解決空指針異常,類聲明如下:
public final class Optional<T> {}java.util.Optional類是一個封裝了Optional值的容器對象,Optional值可以為null,如果值存在,調用isPresent()方法返回true,調用get()方法可以獲取值。通過源代碼會發現,它并沒有實現java.io.Serializable接口,因此應避免在類屬性中使用,防止意想不到的問題。除了Optional類之外,還擴展了一些常用類型的Optional對象,比如:OptionalDouble、OptionalInt、OptionalLong。用法基本上相似。
二、創建Optional對象
創建Optional對象有三種方法:empty()、of()、ofNullable(),均為靜態方法。
- 如果Optional對象沒有值則用empty()方法。
- 如果確定Optional對象的值不為null,則可用of()方法。
- 如果不確定Optional對象的值是否為null,則可用ofNullable()。比如上面,不確定Person對象是不否null,就用了ofNullable()方法。當然,也可以直接給該方法傳null。
此時,通過調用其isPresent方法可以查看該Optional中是否值為null。
boolean bool = ofNullOptional.isPresent(); System.out.println(bool);此時如果直接調用get方法獲取值,則會拋出異常。
通過get方法可獲取Optional中的值,但如果值為null,則會拋出異常。
- isPresent()。
如果Optional實例有值則為其調用consumer ,否則不做處理。 要理解ifPresent方法,首先需要了解Consumer類。簡答地說,Consumer類包含一個抽象方法。該抽象方法對傳入的值進行處理,但沒有返回值。Java8支持不用接口直接通過lambda表達式傳入參數。 如果Optional實例有值,調用ifPresent()可以接受接口段或lambda表達式。類似下面的代碼:
// ifPresent方法接受lambda表達式作為參數。 // lambda表達式對Optional的值調用consumer進行處理。 username.ifPresent((value) -> {System.out.println("The length of the value is: " + value.length());- orElse
如果有值則將其返回,否則返回指定的其它值。 如果Optional實例有值則將其返回,否則返回orElse方法傳入的參數。示例如下:
// 如果值不為null,orElse方法返回Optional實例的值,否則返回傳入的消息 System.out.println(empty.orElse("There is no value present!"));// 輸出:There is no value present! System.out.println(username.orElse("There is some value!"));- orElseGet
orElseGet與orElse方法類似,區別在于得到的默認值。orElse方法將傳入的字符串作為默認值,orElseGet方法可以接受Supplier接口的實現用來生成默認值。示例如下:
// orElseGet與orElse方法類似,區別在于orElse傳入的是默認值, // orElseGet可以接受一個lambda表達式生成默認值。 // 輸出:Default Value System.out.println(empty.orElseGet(() -> "Default Value")); // 輸出:cwl System.out.println(username.orElseGet(() -> "Default Value"));- orElseThrow
如果有值則將其返回,否則拋出supplier接口創建的異常。 在orElseGet方法中,我們傳入一個Supplier接口。然而,在orElseThrow中我們可以傳入一個lambda表達式或方法,如果值不存在來拋出異常。示例如下:
try {// orElseThrow與orElse方法類似。與返回默認值不同,// orElseThrow會拋出lambda表達式或方法生成的異常empty.orElseThrow(ValueAbsentException::new); } catch (Throwable ex) {//輸出: No value present in the Optional instanceSystem.out.println(ex.getMessage()); }ValueAbsentException定義如下:
class ValueAbsentException extends Throwable {public ValueAbsentException() {super();}public ValueAbsentException(String msg) {super(msg);}@Overridepublic String getMessage() {return "No value present in the Optional instance";} }- map
如果有值,則對其執行調用mapping函數得到返回值。如果返回值不為null,則創建包含mapping返回值的Optional作為map方法返回值,否則返回空Optional。 map方法用來對Optional實例的值執行一系列操作。通過一組實現了Function接口的lambda表達式傳入操作。如果你不熟悉Function接口,可以參考這篇博客。map方法示例如下:
// map方法執行傳入的lambda表達式參數對Optional實例的值進行修改。 // 為lambda表達式的返回值創建新的Optional實例作為map方法的返回值。 Optional<String> upperName = username.map((value) -> value.toUpperCase()); System.out.println(upperName.orElse("No value found"));- flatMap
如果有值,為其執行mapping函數返回Optional類型返回值,否則返回空Optional。flatMap與map(Funtion)方法類似,區別在于flatMap中的mapper返回值必須是Optional。調用結束時,flatMap不會對結果用Optional封裝。 參照map函數,使用flatMap重寫的示例如下:
// flatMap與map(Function)非常類似,區別在于傳入方法的lambda表達式的返回類型。 // map方法中的lambda表達式返回值可以是任意類型,在map函數返回之前會包裝為Optional。 // 但flatMap方法中的lambda表達式返回值必須是Optionl實例。 upperName = username.flatMap((value) -> Optional.of(value.toUpperCase()));System.out.println(upperName.orElse("No value found"));- filter
filter個方法通過傳入限定條件對Optional實例的值進行過濾。文檔描述如下: 如果有值并且滿足斷言條件返回包含該值的Optional,否則返回空Optional。 讀到這里,可能你已經知道如何為filter方法傳入一段代碼。是的,這里可以傳入一個lambda表達式。對于filter函數我們應該傳入實現了Predicate接口的lambda表達式。現在看看filter的各種用法,下面的示例介紹了滿足限定條件和不滿足兩種情況:
// filter方法檢查給定的Option值是否滿足某些條件。 // 如果滿足則返回同一個Option實例,否則返回空Optional。 Optional<String> longName = username.filter((value) -> value.length() > 2); System.out.println(longName.orElse("The name is less than 2 characters")); // 另一個例子是Optional值不滿足filter指定的條件。 Optional<String> anotherName = Optional.of("y"); Optional<String> shortName = anotherName.filter((value) -> value.length() > 2); // 輸出:The name is less than 2 characters System.out.println(shortName.orElse("The name is less than 2 characters"));- 結合理解
參考文章
總結
以上是生活随笔為你收集整理的Java8新特性 Optional类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021中国家居行业洞察白皮书
- 下一篇: 常用中后台交互设计控件使用场景与规范总结