Java8 新特性之 Optional 類
摘要: Optional不是對null關鍵字的一種替代,而是對於null判定提供了一種更加優雅的實現
Java8新特性系列
- Java8新特性(一) – lambda表示式
- Java8新特性(二) – Optional類
- Java8新特性(三) – 流式資料處理
- Java8新特性(四) – 預設介面方法
- 待定
NullPointException可以說是所有java程式設計師都遇到過的一個異常,雖然java從設計之初就力圖讓程式設計師脫離指標的苦海,但是指標確實是實際存在的,而java設計者也只能是讓指標在java語言中變得更加簡單、易用,而不能完全的將其剔除,所以才有了我們日常所見到的關鍵字null
。
空指標異常是一個執行時異常,對於這一類異常,如果沒有明確的處理策略,那麼最佳實踐在於讓程式早點掛掉,但是很多場景下,不是開發人員沒有具體的處理策略,而是根本沒有意識到空指標異常的存在。當異常真的發生的時候,處理策略也很簡單,在存在異常的地方新增一個if語句判定即可,但是這樣的應對策略會讓我們的程式出現越來越多的null判定,我們知道一個良好的程式設計,應該讓程式碼中儘量少出現null關鍵字,而java8所提供的Optional
類則在減少NullPointException的同時,也提升了程式碼的美觀度。但首先我們需要明確的是,它並 不是對null
關鍵字的一種替代,而是對於null判定提供了一種更加優雅的實現,從而避免NullPointException。
一. 直觀感受
假設我們需要返回一個字串的長度,如果不借助第三方工具類,我們需要呼叫str.length()
方法:
if(null == str) { // 空指標判定 return 0; } return str.length();
如果採用Optional類,實現如下:
return Optional.ofNullable(str).map(String::length).orElse(0);
Optional的程式碼相對更加簡潔,當程式碼量較大時,我們很容易忘記進行null判定,但是使用Optional類則會避免這類問題。
二. 基本使用
1.物件建立
建立空物件
Optional<String> optStr = Optional.empty();
上面的示例程式碼呼叫empty()
方法建立了一個空的Optional<String>
物件型。
建立物件:不允許為空
Optional提供了方法of()
用於建立非空物件,該方法要求傳入的引數不能為空,否則拋NullPointException
,示例如下:
Optional<String> optStr = Optional.of(str); // 當str為null的時候,將丟擲NullPointException
建立物件:允許為空
如果不能確定傳入的引數是否存在null值的可能性,則可以用Optional的ofNullable()
方法建立物件,如果入參為null,則建立一個空物件。示例如下:
Optional<String> optStr = Optional.ofNullable(str); // 如果str是null,則建立一個空物件
2.流式處理
流式處理也是java8給我們帶來的一個重量級新特性,讓我們對集合的操作變得更加簡潔和高效,下一篇關於java8新特性的文章,將對流失處理進行全面的講解。這裡Optional也提供了兩個基本的流失處理:對映和過濾。
為了演示,我們設計了一個User
類,如下:
/** * @author: zhenchao.Wang 2016-9-24 15:36:56 */ public class User { /** 使用者編號 */ private long id; private String name; private int age; private Optional<Long> phone; private Optional<String> email; public User(String name, int age) { this.name = name; this.age = age; } // 省略setter和getter }
手機和郵箱不是一個人的必須有的,所以我們利用Optional定義。
對映:map與flatMap
對映是將輸入轉換成另外一種形式的輸出的操作,比如前面例子中,我們輸入字串,而輸出的是字串的長度,這就是一種隱射,我們利用方法map()
得以實現。假設我們希望獲得一個人的姓名,那麼我們可以如下實現:
String name = Optional.ofNullable(user).map(User::getName).orElse("no name");
這樣當入參user不為空的時候則返回其name,否則返回no name
如我我們希望通過上面方式得到phone或email,利用上面的方式則行不通了,因為map之後返回的是Optional,我們把這種稱為Optional巢狀,我們必須在map一次才能拿到我們想要的結果:
long phone = optUser.map(User::getPhone).map(Optional::get).orElse(-1L);
其實這個時候,更好的方式是利用flatMap,一步拿到我們想要的結果:
long phone = optUser.flatMap(User::getPhone).orElse(-1L);
flapMap可以將方法返回的各個流扁平化成為一個流,具體在下一篇專門講流式處理的文章中細說。
過濾:fliter
filiter,顧名思義是過濾的操作,我們可以將過濾操作做為引數傳遞給該方法,從而實現過濾目的,加入我們希望篩選18週歲以上的成年人,則可以實現如下:
optUser.filter(u -> u.getAge() >= 18).ifPresent(u -> System.out.println("Adult:" + u));
3.預設行為
預設行為是當Optional為不滿足條件時所執行的操作,比如在上面的例子中我們使用的orElse()
就是一個預設操作,用於在Optional物件為空時執行特定操作,當然也有一些預設操作是當滿足條件的物件存在時執行的操作。
get()
get用於獲取變數的值,但是當變數不存在時則會丟擲NoSuchElementException
,所以如果不確定變數是否存在,則不建議使用
orElse(T other)
當Optional的變數不滿足給定條件時,則執行orElse,比如前面當str為null時,返回0。
orElseGet(Supplier<? extends X> expectionSupplier)
如果條件不成立時,需要執行相對複雜的邏輯,而不是簡單的返回操作,則可以使用orElseGet實現:
long phone = optUser.map(User::getPhone).map(Optional::get).orElseGet(() -> { // do something here return -1L; });
orElseThrow(Supplier<? extends X> expectionSupplier)
與get()方法類似,都是在不滿足條件時返回異常,不過這裡我們可以指定返回的異常型別。
ifPresent(Consumer<? super T>)
當滿足條件時執行傳入的引數化操作。
三. 注意事項
Optional是一個final類,未實現任何介面,所以當我們在利用該類包裝定義類的屬性的時候,如果我們定義的類有序列化的需求,那麼因為Optional沒有實現Serializable介面,這個時候執行序列化操作就會有問題:
public class User implements Serializable{ /** 使用者編號 */ private long id; private String name; private int age; private Optional<Long> phone; // 不能序列化 private Optional<String> email; // 不能序列化
不過我們可以採用如下替換策略:
private long phone; public Optional<Long> getPhone() { return Optional.ofNullable(this.phone); }
看來Optional在設計的時候就沒有考慮將它作為類的欄位使用~
相關文章
- ?Java8新特性之Optional類Java
- java8 新特性之Optional 類Java
- Java8新特性之:OptionalJava
- java8特性 Optional 工具類Java
- Java8新特性之空指標異常的剋星Optional類Java指標
- Java 8 新特性---Optional類Java
- Java 8新特性(三):Optional類Java
- Java8 Optional類Java
- 【Java8新特性】不瞭解Optional類,簡歷上別說你懂Java8!!Java
- 講講Java8的Optional類Java
- java8 新特性之方法引用Java
- java8 新特性之Lambda 表示式Java
- java8 新特性之預設方法Java
- Java8新特性探索之Stream介面Java
- Java8 新特性之 Lambda 表示式Java
- Java8新特性之時間APIJavaAPI
- Java8 Lambda表示式、Optional類淺析Java
- JAVA8新特性Java
- Java8 新特性Java
- JDK1.8新特性值OptionalJDK
- java8 新特性之函式式介面Java函式
- java8新特性之lambda表示式(一)Java
- Java8 新特性之預設介面方法Java
- java8 之 Java官方庫的新特性Java
- Java8新特性 - LambdaJava
- Java8的新特性Java
- JAVA8新特性用法Java
- Java8新特性探索之函式式介面Java函式
- Java8新特性探索之新日期時間庫Java
- Java8新特性--Stream APIJavaAPI
- java8新特性stream流Java
- Java8新特性實踐Java
- Java8新特性系列-LambdaJava
- Java8新特性系列(Stream)Java
- Java8新特性系列(Interface)Java
- Java8新特性系列(Lambda)Java
- Java8 新特性詳解Java
- java8新特性學習Java