摘要:當滿足條件時執行傳入的參數化操作。最后提醒一點,好用但不能濫用,在設計一個接口方法時是否采取類型返回需要斟酌,一味的使用會讓代碼變得比較啰嗦,反而破壞了代碼的簡潔性。鑒于作者水平有限,文中不免有錯誤之處,歡迎批評指正個人博客
NullPointException 可以說是所有 java 程序員都遇到過的一個異常,雖然 java 從設計之初就力圖讓程序員脫離指針的苦海,但是指針確實是實際存在的,而 java 設計者也只能是讓指針在 java 語言中變得更加簡單、易用,而不能完全的將其剔除,所以才有了我們日常所見到的關鍵字 null。
空指針異常是一個運行時異常,對于這一類異常,如果沒有明確的處理策略,那么最佳實踐在于讓程序早點掛掉,但是很多場景下不是開發人員沒有具體的處理策略,而是根本沒有意識到空指針異常的存在。當異常真的發生的時候,處理策略也很簡單,在存在異常的地方添加一個 if 語句判定即可,但是這樣的應對策略會讓我們的程序出現越來越多的 null 判定。一個良好的程序設計應該讓代碼中盡量少出現 null 關鍵字,而 8th 所提供的 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.1 Optional 對象的創建創建空對象
OptionaloptStr = Optional.empty();
上面的示例代碼調用 empty() 方法創建了一個空的 Optional
創建對象:不允許我空
Optional 提供了方法 of() 用于創建非空對象,該方法要求傳入的參數不能為空,否則拋 NullPointException,示例如下:
OptionaloptStr = Optional.of(str); // 當str為null的時候,將拋出NullPointException
創建對象:允許為空
如果不能確定傳入的參數是否存在 null 值的可能性,則可以用 Optional 的 ofNullable() 方法創建對象,如果入參為 null 則創建一個空對象。示例如下:
Optional1.2 流式數據處理optStr = Optional.ofNullable(str); // 如果str是null,則創建一個空對象
流式數據處理也是 8th 給我們帶來的一個重量級新特性,讓我們對集合的操作變得更加簡潔和高效,本系列下一篇將對流式數據處理進行全面的講解。Optional 類也提供了兩個基本的流失處理:映射和過濾。
為了演示,我們設計了一個 User 類,如下:
public class User { private long id; private String name; private int age; private Optionalphone; private Optional 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));1.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 Optionalphone; // 不能序列化 private Optional email; // 不能序列化 }
不過我們可以采用如下替換策略 Optinal:
private long phone; public OptionalgetPhone() { return Optional.ofNullable(this.phone); }
看來 Optional 類在設計的時候就沒有考慮將它作為類的字段使用。
最后提醒一點,Optional 好用但不能濫用,在設計一個接口方法時是否采取 Optional 類型返回需要斟酌,一味的使用會讓代碼變得比較啰嗦,反而破壞了代碼的簡潔性。
鑒于作者水平有限,文中不免有錯誤之處,歡迎批評指正
個人博客:www.zhenchao.org
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/70647.html
摘要:自定義函數式接口我們在前面例子中實現的蘋果篩選接口就是一個函數式接口定義如下,正因為如此我們可以將篩選邏輯參數化,并應用表達式僅包含一個抽象方法,依照定義可以將其視為一個函數式接口。 Lambda 表達式是 java 8th 給我們帶來的幾個重量級新特性之一,借用 lambda 表達式可以讓我們的程序設計更加簡潔。最近新的項目摒棄了 6th 版本,全面基于 8th 進行開發,本文將探討...
摘要:新特性總覽標簽本文主要介紹的新特性,包括表達式方法引用流默認方法組合式異步編程新的時間,等等各個方面。還有對應的和類型的函數連接字符串廣義的歸約匯總起始值,映射方法,二元結合二元結合。使用并行流時要注意避免共享可變狀態。 Java8新特性總覽 標簽: java [TOC] 本文主要介紹 Java 8 的新特性,包括 Lambda 表達式、方法引用、流(Stream API)、默認方...
大概一年多之前,我對java8的理解還僅限一些只言片語的文章之上,后來出于對函數式編程的興趣,買了本參考書看了一遍,然后放在了書架上,后來,當我接手大客戶應用的開發工作之后,java8的一些工具,對我的效率有了不小的提升,因此想記錄一下java8的一些常用場景,我希望這會成為一個小字典,能讓我免于頻繁翻書,但是總能找到自己想找的知識。 用于舉例的model: @Data public class ...
摘要:函數副作用會給程序設計帶來不必要的麻煩,引入潛在的,并降低程序的可讀性。所以只能采用這種曲線救國的方式。則是把這種曲線救國拿到了臺面上,并昭告天下,同時還對提供了一些語法支持。是自由變量,提供執行上下文,觸發閉包執行。 背景 自從2013年放棄了Java就再也沒有碰過。期間Java還發布了重大更新:引入lambda,但是那會兒我已經玩了一段時間Scala,對Java已經瞧不上眼。相比S...
閱讀 3108·2021-09-22 15:54
閱讀 3996·2021-09-09 11:34
閱讀 1778·2019-08-30 12:48
閱讀 1169·2019-08-30 11:18
閱讀 3439·2019-08-26 11:48
閱讀 923·2019-08-23 17:50
閱讀 2125·2019-08-23 17:17
閱讀 1250·2019-08-23 17:12