java8-Optional的實(shí)戰(zhàn)應(yīng)用

Optional的學(xué)習(xí)與實(shí)戰(zhàn)

整片文章大部分內(nèi)容來(lái)自java8實(shí)戰(zhàn)這本書(shū),我在這里也是將自己的學(xué)習(xí)過(guò)程記錄下來(lái),并且整理成筆記給需要的人提供一個(gè)方便,在學(xué)習(xí)的過(guò)程中主要有以下幾點(diǎn)疑惑:

不明白Optional的作用是什么?

不清楚在什么情況下使用Optional?

面對(duì)多層嵌套的情況Optional如何拆解?

Optional和Stream之間的關(guān)系?

寫(xiě)在前面

作為一個(gè)java開(kāi)發(fā)程序猿如果說(shuō)你沒(méi)有遇到過(guò)空指針的問(wèn)題,那真的是太神奇了,在我們的工作中,常常會(huì)想盡一切辦法避免空指針的.事實(shí)上也有人曾經(jīng)提出空引用的想法,就是對(duì)null依然進(jìn)行引用,但是這種做法所帶來(lái)的可怕影響就是會(huì)在后期帶啦大量的NullPrinterException異常.

本文的目的是使用Optional來(lái)取代null,并且使用Optional來(lái)去除代碼中大量的null檢查從而提高我們程序的可讀性和代碼的健壯性.

Null帶來(lái)的種種問(wèn)題

錯(cuò)誤之源:NullPointExpection是java開(kāi)發(fā)中最經(jīng)常遭遇的異常.

是你的代碼膨脹:頁(yè)面中充斥著過(guò)多而null檢查,是代碼的可讀性大大降低.

自身毫無(wú)意義:自身沒(méi)有任何意義,這本身就是一種錯(cuò)誤的建模.

破壞了java的哲學(xué)性:java一直試圖讓人們避免接觸指針的問(wèn)題,但是null是唯一的例外

在java類(lèi)型系統(tǒng)上開(kāi)了一個(gè)口子:null并不屬于任何類(lèi)型,這意味著他可以賦值給任意變量.

其他語(yǔ)言中null的替代品

在Groovy中可以通過(guò)安全導(dǎo)航操作符(Safe Navigation Operator,標(biāo)記為?)

carInsuranceName= person?.car?.insurance?.name

1

在使用變量是可能出現(xiàn)null的情況,但是在這種情況下不會(huì)拋出空指針的異常,而是將null沿著調(diào)用鏈一直傳遞下去.最終返回一個(gè)null.

在java8中引入了Optional的概念設(shè)置了一個(gè)新的類(lèi)java.util.Option的類(lèi)型,從而對(duì)可能出現(xiàn)null的對(duì)象進(jìn)行建模

Optional類(lèi)入門(mén)

如果我們需要使用一個(gè)對(duì)象,這個(gè)對(duì)象中可能存在null,我們可以聲明其為Optional類(lèi)型,變量存在是返回的是封裝的對(duì)象,當(dāng)變量不存在使返回的是一個(gè)空的Optional對(duì)象.在語(yǔ)法上你可以把這個(gè)當(dāng)做一回事,但是實(shí)際中他們之間存才非常大的差別.如果你引用的是一個(gè)null,一定會(huì)觸發(fā)NullPointException

,如果使用Optional.empty()就完全沒(méi)有事.

**使用Optional而不是null是一個(gè)非常重要而又實(shí)際的語(yǔ)義區(qū)別.

使用Optional對(duì)你的代碼進(jìn)行重構(gòu).

public class EssayCompositeQuestionDot {

? ? /**

? ? * paper name

? ? */

? ? private String paperName;

? ? /**

? ? * paper id

? ? */

? ? private int paperId;

? ? /**

? ? * Check to see if the object highlighted

? ? * In this class 'flag' default 'true'

? ? */

? ? private boolean flag = true;

? ? private List<Optional<StemList>> stemList = new LinkedList<>();

? ? private List<Optional<MaterialList>> materialList = new LinkedList<>();

? ? @Data

? ? @NoArgsConstructor

? ? @AllArgsConstructor

? ? public class MaterialList {

? ? ? ? /**

? ? ? ? * material id

? ? ? ? */

? ? ? ? private Integer id;

? ? ? ? /**

? ? ? ? * material content

? ? ? ? */

? ? ? ? private String content;

? ? ? ? /**

? ? ? ? * Check to see if the object highlighted

? ? ? ? */

? ? ? ? private boolean flag = false;

? ? }

? ? @Data

? ? @NoArgsConstructor

? ? @AllArgsConstructor

? ? public class StemList {

? ? ? ? /**

? ? ? ? * stem baseId

? ? ? ? */

? ? ? ? private Integer baseId;

? ? ? ? /**

? ? ? ? * stem detailId

? ? ? ? */

? ? ? ? private Integer detailId;

? ? ? ? /**

? ? ? ? * stem content

? ? ? ? */

? ? ? ? private String content;

? ? ? ? /**

? ? ? ? * Check to see if the object highlighted

? ? ? ? */

? ? ? ? private boolean flag = false;

? ? }

創(chuàng)建Optioanl對(duì)象

Optional提供了集中靜態(tài)方法供我們直接使用

聲明一個(gè)空的Optional

直接調(diào)用靜態(tài)工廠的方法Optional.empty創(chuàng)建一個(gè)對(duì)象

? ? Optional<EssayQuestionGroupResponse> empty = Optional.empty();

1

根據(jù)非空值創(chuàng)建Optional

直接調(diào)用講臺(tái)方法Optional.of,依據(jù)一個(gè)非空值創(chuàng)建一個(gè)Optional對(duì)象

? ? Optional<EssayQuestionGroupResponse> essayQuestionGroupResponse = Optional.of(new EssayQuestionGroupResponse());

可接受null的Optional

使用講臺(tái)工廠方法Optional.ofNullable創(chuàng)建一個(gè)允許null值得Optional對(duì)象

EssayQuestionGroupResponse essayQuestionGroupResponseNull = new EssayQuestionGroupResponse();

? ? ? ? Optional<EssayQuestionGroupResponse> essayQuestionGroupResponseNullOptional = Optional.ofNullable(essayQuestionGroupResponseNull);

獲取Optional中的對(duì)象

我們將對(duì)象放到了Optional中,他們本身提供了一個(gè)get方法,但是如果我們不按照約定進(jìn)行g(shù)et那么他依然會(huì)拋出一個(gè)NullException

? ? EssayQuestionGroupResponse essayQuestionGroupResponseNull = new EssayQuestionGroupResponse();

? ? ? ? System.out.println(essayQuestionGroupResponse.map(EssayQuestionGroupResponse::getGroupId).get());

Exception in thread "main" java.util.NoSuchElementException: No value present

at java.util.Optional.get(Optional.java:135)

at com.huatu.search.optional.OptionalGetTest.main(OptionalGetTest.java:19)

使用map從optional對(duì)象中提取和轉(zhuǎn)化值

從對(duì)象中提取信息這是很常見(jiàn)的模式,Optional提供了一個(gè)map方法,他的工作方式如下.

essayQuestionGroupResponse.map(EssayQuestionGroupResponse::getGroupId);

同學(xué)們也很容易發(fā)現(xiàn),如果想要獲取嵌套對(duì)象,讓然使用map是不可取的,這里需要使用flatMap

essayQuestionGroupResponse

? ? ? ? .flatMap(EssayQuestionGroupResponse::getMaterialList)

? ? ? ? .map(EssayQuestionGroupResponse.Material::getMaterialContent).orElse("null"))

在最后使用orElse如果在調(diào)用鏈中的認(rèn)識(shí)一環(huán)出現(xiàn)空指針則會(huì)返回orElse中的內(nèi)容

? ? Optional<EssayQuestionGroupResponse> essayQuestionGroupResponse = Optional.of(new EssayQuestionGroupResponse());

? ? ? ? //這里會(huì)出現(xiàn)空值,以后在研究

? ? ? ? System.out.println(essayQuestionGroupResponse

? ? ? ? ? ? ? ? .flatMap(EssayQuestionGroupResponse::getMaterialList)

? ? ? ? ? ? ? ? .map(Material::getMaterialContent).orElse("null"));

? ? }

默認(rèn)行為以及街引用Optional對(duì)象

再生產(chǎn)中有如下幾種方式獲取到Optional中的對(duì)象

get()是最簡(jiǎn)單的方法,并且不安全,如果變量存在直接返回封裝的變量值,否做就跑出一個(gè)NoSuchElementException異常 .

orElse(T other)當(dāng)Optional中不包含值得時(shí)候提供一個(gè)默認(rèn)值.

orElseGet(Supplier<? extends T>)是上一個(gè)方法的延時(shí)調(diào)用版,需要提高性能可以使用此方法.

orElseThrow(Supplier<? extends exceptionSupplier>)如果對(duì)象為空的時(shí)候回拋出一個(gè)異常.

ifPresent(Consumer<? super T>) 讓變量在存在的時(shí)候作為一個(gè)消費(fèi)者傳入一個(gè)方法否則不執(zhí)行任何操作.

實(shí)戰(zhàn)實(shí)例

有效的使用Optional類(lèi)意味著在需要處理潛在缺失值得時(shí)候可以進(jìn)行全面的反思了.

用Optional封裝可能為null的值

現(xiàn)存的很多方法都是通過(guò)返回一個(gè)null來(lái)表示沒(méi)有這個(gè)值,就好比我們經(jīng)常使用的map.get()方法,如果該map中不存在對(duì)應(yīng)屬性則會(huì)返回一個(gè)null.這是用Optional將代碼封裝起來(lái)就可以減少if-else的判斷.

Optional<String> value=Optional.ofNullable(map.get("key"));

每次在獲取潛為null的對(duì)象時(shí)都可以調(diào)用這個(gè)方法.

異常與Optional的對(duì)比

由于某種原因,函數(shù)無(wú)法返回某個(gè)值,這是除了返回null,JavaAPI通常的做法是拋出一個(gè)異常.這種情況比較典型的例子就是Integer.parseInt(String),如果轉(zhuǎn)化失敗則會(huì)拋出一個(gè)NumberFormatException,這種情況和之前的null相比唯一不同的處理方法就是使用try/catch,而之前是使用if/else進(jìn)行判斷.這時(shí)候我們可以用如下的方式完成這個(gè)功能.

public static Optional<Integer> stringToInt (String s) {

? ? try {

? ? ? ? return Optional.of(Integer.parseInt(s);

? ? } catch (NumberFormatException e) {

? ? ? ? return Optional.empty();

? ? }

}

我們可以將多中類(lèi)似的方法封裝到一個(gè)工具類(lèi)中進(jìn)行使用.

總結(jié)

整片文章大部分內(nèi)容來(lái)自java8實(shí)戰(zhàn)這本書(shū),我在這里也是將自己的學(xué)習(xí)過(guò)程記錄下來(lái),并且整理成筆記給需要的人提供一個(gè)方便,在學(xué)習(xí)的過(guò)程中主要有以下幾點(diǎn)疑惑:

不明白Optional的作用是什么?

不清楚在什么情況下使用Optional?

面對(duì)多層嵌套的情況Optional如何拆解?

Optional和Stream之間的關(guān)系?

通過(guò)系統(tǒng)的學(xué)習(xí)以上幾點(diǎn)疑惑基本都已經(jīng)解決了,在今后的開(kāi)發(fā)中也將開(kāi)始大量使用Optional這個(gè)方法來(lái)幫助自己的代碼提高安全性和可讀性.最后再附上一張思維導(dǎo)圖用來(lái)描述Optional的總體概況

思維導(dǎo)圖


 在此我向大家推薦一個(gè)架構(gòu)學(xué)習(xí)交流群。交流學(xué)習(xí)群號(hào):938837867 暗號(hào):555 里面會(huì)分享一些資深架構(gòu)師錄制的視頻錄像:有Spring随常,MyBatis萄涯,Netty源碼分析涝影,高并發(fā)、高性能序目、分布式、微服務(wù)架構(gòu)的原理刻蟹,JVM性能優(yōu)化嘿辟、分布式架構(gòu)等這些成為架構(gòu)師必備

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末红伦,一起剝皮案震驚了整個(gè)濱河市昙读,隨后出現(xiàn)的幾起案子召调,更是在濱河造成了極大的恐慌,老刑警劉巖蛮浑,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唠叛,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡沮稚,警方通過(guò)查閱死者的電腦和手機(jī)艺沼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蕴掏,“玉大人障般,你說(shuō)我怎么就攤上這事∈⒔埽” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵即供,是天一觀的道長(zhǎng)定拟。 經(jīng)常有香客問(wèn)我,道長(zhǎng)逗嫡,這世上最難降的妖魔是什么办素? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮祸穷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘勺三。我一直安慰自己雷滚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布吗坚。 她就那樣靜靜地躺著祈远,像睡著了一般呆万。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上车份,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天谋减,我揣著相機(jī)與錄音,去河邊找鬼扫沼。 笑死出爹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缎除。 我是一名探鬼主播严就,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼器罐!你這毒婦竟也來(lái)了梢为?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤轰坊,失蹤者是張志新(化名)和其女友劉穎铸董,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體肴沫,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡粟害,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了樊零。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片我磁。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖驻襟,靈堂內(nèi)的尸體忽然破棺而出夺艰,到底是詐尸還是另有隱情,我是刑警寧澤沉衣,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布郁副,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏溢谤。R本人自食惡果不足惜返顺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望既荚。 院中可真熱鬧,春花似錦栋艳、人聲如沸恰聘。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)晴叨。三九已至凿宾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間兼蕊,已是汗流浹背初厚。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留孙技,地道東北人产禾。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像绪杏,于是被迫代替她去往敵國(guó)和親下愈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 關(guān)于java8 Optional 文檔版本:v1.0版本 和C/C++不一樣蕾久,java從一開(kāi)始就嘗試將指針徹底的包...
    比軒閱讀 3,749評(píng)論 1 22
  • (一)Java部分 1势似、列舉出JAVA中6個(gè)比較常用的包【天威誠(chéng)信面試題】 【參考答案】 java.lang;ja...
    獨(dú)云閱讀 7,107評(píng)論 0 62
  • Optional 本章內(nèi)容 如何為缺失的值建模 Optional 類(lèi) 應(yīng)用Optional的幾種模式 使用Opti...
    追憶逝水年華閱讀 1,798評(píng)論 0 0
  • 從大學(xué)開(kāi)始便努力的學(xué)習(xí)著一個(gè)人,直到現(xiàn)在大二快要過(guò)去僧著,大三即將到來(lái)履因,我卻始終學(xué)不會(huì)一個(gè)人。去上課的路上會(huì)瘋狂的...
    愛(ài)是久處不厭1閱讀 285評(píng)論 0 0
  • 在這個(gè)宿舍一直聽(tīng)著大喇叭里毛阿敏唱的《思念》韋唯唱的《亞洲雄風(fēng)》度過(guò)一個(gè)禮拜盹愚,天天就集合跑步……終于大集合栅迄,中校軍...
    老兵一個(gè)閱讀 182評(píng)論 0 1