摘要:當(dāng)滿足條件時(shí)執(zhí)行傳入的參數(shù)化操作。最后提醒一點(diǎn),好用但不能濫用,在設(shè)計(jì)一個(gè)接口方法時(shí)是否采取類型返回需要斟酌,一味的使用會(huì)讓代碼變得比較啰嗦,反而破壞了代碼的簡潔性。鑒于作者水平有限,文中不免有錯(cuò)誤之處,歡迎批評(píng)指正個(gè)人博客
NullPointException 可以說是所有 java 程序員都遇到過的一個(gè)異常,雖然 java 從設(shè)計(jì)之初就力圖讓程序員脫離指針的苦海,但是指針確實(shí)是實(shí)際存在的,而 java 設(shè)計(jì)者也只能是讓指針在 java 語言中變得更加簡單、易用,而不能完全的將其剔除,所以才有了我們?nèi)粘K姷降年P(guān)鍵字 null。
空指針異常是一個(gè)運(yùn)行時(shí)異常,對(duì)于這一類異常,如果沒有明確的處理策略,那么最佳實(shí)踐在于讓程序早點(diǎn)掛掉,但是很多場(chǎng)景下不是開發(fā)人員沒有具體的處理策略,而是根本沒有意識(shí)到空指針異常的存在。當(dāng)異常真的發(fā)生的時(shí)候,處理策略也很簡單,在存在異常的地方添加一個(gè) if 語句判定即可,但是這樣的應(yīng)對(duì)策略會(huì)讓我們的程序出現(xiàn)越來越多的 null 判定。一個(gè)良好的程序設(shè)計(jì)應(yīng)該讓代碼中盡量少出現(xiàn) null 關(guān)鍵字,而 8th 所提供的 Optional 類則在減少 NullPointException 的同時(shí),也提升了代碼的美觀度。但首先我們需要明確的是它并 不是對(duì) null 關(guān)鍵字的替代策略,而是對(duì)于 null 判定提供了一種更加優(yōu)雅的實(shí)現(xiàn),從而盡可能地避免 NullPointException 。
下面通過一個(gè)小示例直觀感受一下,假設(shè)我們需要返回一個(gè)字符串的長度,如果不借助第三方工具類,我們需要調(diào)用 str.length() 方法:
if(null == str) { // 空指針判定 return 0; } return str.length();
如果采用 Optional 類,實(shí)現(xiàn)如下:
return Optional.ofNullable(str).map(String::length).orElse(0);
Optional 的代碼相對(duì)更加簡潔,當(dāng)代碼量較大時(shí),我們很容易忘記進(jìn)行 null 判定,但是使用 Optional 類則會(huì)避免這類問題。
一. 基本使用 1.1 Optional 對(duì)象的創(chuàng)建創(chuàng)建空對(duì)象
OptionaloptStr = Optional.empty();
上面的示例代碼調(diào)用 empty() 方法創(chuàng)建了一個(gè)空的 Optional
創(chuàng)建對(duì)象:不允許我空
Optional 提供了方法 of() 用于創(chuàng)建非空對(duì)象,該方法要求傳入的參數(shù)不能為空,否則拋 NullPointException,示例如下:
OptionaloptStr = Optional.of(str); // 當(dāng)str為null的時(shí)候,將拋出NullPointException
創(chuàng)建對(duì)象:允許為空
如果不能確定傳入的參數(shù)是否存在 null 值的可能性,則可以用 Optional 的 ofNullable() 方法創(chuàng)建對(duì)象,如果入?yún)?null 則創(chuàng)建一個(gè)空對(duì)象。示例如下:
Optional1.2 流式數(shù)據(jù)處理optStr = Optional.ofNullable(str); // 如果str是null,則創(chuàng)建一個(gè)空對(duì)象
流式數(shù)據(jù)處理也是 8th 給我們帶來的一個(gè)重量級(jí)新特性,讓我們對(duì)集合的操作變得更加簡潔和高效,本系列下一篇將對(duì)流式數(shù)據(jù)處理進(jìn)行全面的講解。Optional 類也提供了兩個(gè)基本的流失處理:映射和過濾。
為了演示,我們?cè)O(shè)計(jì)了一個(gè) 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 }
手機(jī)和郵箱不是一個(gè)人的必須有的,所以我們利用 Optional 類定義。
映射:map 與 flatMap
映射是將輸入轉(zhuǎn)換成另外一種形式的輸出的操作,比如前面例子中我們輸入字符串,而輸出的是字符串的長度,這就是一種映射,我們利用方法 map() 進(jìn)行實(shí)現(xiàn)。假設(shè)我們希望獲得一個(gè)人的姓名,我們可以如下實(shí)現(xiàn):
String name = Optional.ofNullable(user).map(User::getName).orElse("no name");
這樣當(dāng)入?yún)?user 不為空的時(shí)候則返回其 name,否則返回 no name。如我我們希望通過上面方式得到 phone 或 email,利用上面的方式則行不通了,因?yàn)?map 之后返回的是 Optional,我們把這種稱為 Optional 嵌套,我們必須再 map 一次才能拿到我們想要的結(jié)果:
long phone = optUser.map(User::getPhone).map(Optional::get).orElse(-1L);
其實(shí)這個(gè)時(shí)候更好的方式是利用 flatMap,一步拿到我們想要的結(jié)果:
long phone = optUser.flatMap(User::getPhone).orElse(-1L);
flapMap 可以將方法返回的各個(gè)流扁平化成為一個(gè)流,具體在下一篇專門講流式數(shù)據(jù)處理的文章中細(xì)說。
過濾:fliter
filiter,顧名思義是過濾的操作,我們可以將過濾操作做為參數(shù)傳遞給該方法以實(shí)現(xiàn)過濾目的,假如我們希望篩選 18 周歲以上的成年人,則可以實(shí)現(xiàn)如下:
optUser.filter(u -> u.getAge() >= 18).ifPresent(u -> System.out.println("Adult:" + u));1.3 默認(rèn)行為
默認(rèn)行為是當(dāng) Optional 在不滿足條件時(shí)所執(zhí)行的操作,比如在上面的例子中我們使用的 orElse() 就是一個(gè)默認(rèn)操作,用于在 Optional 對(duì)象為空時(shí)執(zhí)行特定操作,當(dāng)然也有一些默認(rèn)操作是當(dāng)滿足條件的對(duì)象存在時(shí)執(zhí)行的操作。
get()
get 方法用于獲取變量的值,但是當(dāng)變量不存在時(shí)則會(huì)拋出 NoSuchElementException,所以如果不確定變量是否存在則不建議使用
orElse(T other)
當(dāng) Optional 的變量不滿足給定條件時(shí),則執(zhí)行 orElse,比如前面當(dāng) str 為 null 時(shí)返回 0。
orElseGet(Supplier extends X> expectionSupplier)
如果條件不成立時(shí)需要執(zhí)行相對(duì)復(fù)雜的邏輯而不是簡單的返回操作,則可以使用 orElseGet 實(shí)現(xiàn):
long phone = optUser.map(User::getPhone).map(Optional::get).orElseGet(() -> { // do something here return -1L; });
orElseThrow(Supplier extends X> expectionSupplier)
與 get() 方法類似,都是在不滿足條件時(shí)返回異常,不過這里我們可以指定返回的異常類型。
ifPresent(Consumer super T>)
當(dāng)滿足條件時(shí)執(zhí)行傳入的參數(shù)化操作。
二. 注意事項(xiàng)Optional 是一個(gè) final 類且未實(shí)現(xiàn)任何接口,所以當(dāng)我們?cè)诶迷擃惏b定義類的屬性的時(shí)候,如果我們定義的類有序列化的需求,那么因?yàn)?Optional 沒有實(shí)現(xiàn) Serializable 接口,這個(gè)時(shí)候執(zhí)行序列化操作就會(huì)有問題:
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 類在設(shè)計(jì)的時(shí)候就沒有考慮將它作為類的字段使用。
最后提醒一點(diǎn),Optional 好用但不能濫用,在設(shè)計(jì)一個(gè)接口方法時(shí)是否采取 Optional 類型返回需要斟酌,一味的使用會(huì)讓代碼變得比較啰嗦,反而破壞了代碼的簡潔性。
鑒于作者水平有限,文中不免有錯(cuò)誤之處,歡迎批評(píng)指正
個(gè)人博客:www.zhenchao.org
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/70647.html
摘要:自定義函數(shù)式接口我們?cè)谇懊胬又袑?shí)現(xiàn)的蘋果篩選接口就是一個(gè)函數(shù)式接口定義如下,正因?yàn)槿绱宋覀兛梢詫⒑Y選邏輯參數(shù)化,并應(yīng)用表達(dá)式僅包含一個(gè)抽象方法,依照定義可以將其視為一個(gè)函數(shù)式接口。 Lambda 表達(dá)式是 java 8th 給我們帶來的幾個(gè)重量級(jí)新特性之一,借用 lambda 表達(dá)式可以讓我們的程序設(shè)計(jì)更加簡潔。最近新的項(xiàng)目摒棄了 6th 版本,全面基于 8th 進(jìn)行開發(fā),本文將探討...
摘要:新特性總覽標(biāo)簽本文主要介紹的新特性,包括表達(dá)式方法引用流默認(rèn)方法組合式異步編程新的時(shí)間,等等各個(gè)方面。還有對(duì)應(yīng)的和類型的函數(shù)連接字符串廣義的歸約匯總起始值,映射方法,二元結(jié)合二元結(jié)合。使用并行流時(shí)要注意避免共享可變狀態(tài)。 Java8新特性總覽 標(biāo)簽: java [TOC] 本文主要介紹 Java 8 的新特性,包括 Lambda 表達(dá)式、方法引用、流(Stream API)、默認(rèn)方...
摘要:但有一個(gè)限制它們不能修改定義的方法的局部變量的內(nèi)容。如前所述,這種限制存在的原因在于局部變量保存在棧上,并且隱式表示它們僅限于其所在線程。 2014年,Oracle發(fā)布了Java8新版本。對(duì)于Java來說,這顯然是一個(gè)具有里程碑意義的版本。尤其是那函數(shù)式編程的功能,避開了Java那煩瑣的語法所帶來的麻煩。 這可以算是一篇Java8的學(xué)習(xí)筆記。將Java8一些常見的一些特性作了一個(gè)概要的...
大概一年多之前,我對(duì)java8的理解還僅限一些只言片語的文章之上,后來出于對(duì)函數(shù)式編程的興趣,買了本參考書看了一遍,然后放在了書架上,后來,當(dāng)我接手大客戶應(yīng)用的開發(fā)工作之后,java8的一些工具,對(duì)我的效率有了不小的提升,因此想記錄一下java8的一些常用場(chǎng)景,我希望這會(huì)成為一個(gè)小字典,能讓我免于頻繁翻書,但是總能找到自己想找的知識(shí)。 用于舉例的model: @Data public class ...
摘要:函數(shù)副作用會(huì)給程序設(shè)計(jì)帶來不必要的麻煩,引入潛在的,并降低程序的可讀性。所以只能采用這種曲線救國的方式。則是把這種曲線救國拿到了臺(tái)面上,并昭告天下,同時(shí)還對(duì)提供了一些語法支持。是自由變量,提供執(zhí)行上下文,觸發(fā)閉包執(zhí)行。 背景 自從2013年放棄了Java就再也沒有碰過。期間Java還發(fā)布了重大更新:引入lambda,但是那會(huì)兒我已經(jīng)玩了一段時(shí)間Scala,對(duì)Java已經(jīng)瞧不上眼。相比S...
閱讀 3108·2021-09-22 15:54
閱讀 3997·2021-09-09 11:34
閱讀 1780·2019-08-30 12:48
閱讀 1171·2019-08-30 11:18
閱讀 3441·2019-08-26 11:48
閱讀 927·2019-08-23 17:50
閱讀 2126·2019-08-23 17:17
閱讀 1252·2019-08-23 17:12