摘要:但返回的是一個(gè)類型的對(duì)象,這意味著操作的結(jié)果是一個(gè)類型的對(duì)象。反之,如果對(duì)象存在,這次調(diào)用就會(huì)將其作為函數(shù)的輸入,并按照與方法的約定返回一個(gè)對(duì)象。
一、Optional 類入門
Java 8中引入了一個(gè)新的類java.util.Optional
的Optional對(duì)象,由方法Optional.empty()返回。
正如前文已經(jīng)提到,你可以通過靜態(tài)工廠方法Optional.empty,創(chuàng)建一個(gè)空的Optional對(duì)象:
Optional(2) 依據(jù)一個(gè)非空值創(chuàng)建OptionaloptCar = Optional.empty();
你還可以使用靜態(tài)工廠方法Optional.of,依據(jù)一個(gè)非空值創(chuàng)建一個(gè)Optional對(duì)象:
OptionaloptCar = Optional.of(car);
如果car是一個(gè)null,這段代碼會(huì)立即拋出一個(gè)NullPointerException,而不是等到你試圖訪問car的屬性值時(shí)才返回一個(gè)錯(cuò)誤。
(3) 可接受null的Optional最后,使用靜態(tài)工廠方法Optional.ofNullable,你可以創(chuàng)建一個(gè)允許null值的Optional對(duì)象:
OptionaloptCar = Optional.ofNullable(car);
如果car是null,那么得到的Optional對(duì)象就是個(gè)空對(duì)象。
Optional提供了一個(gè)get方法用于獲取Optional變量中的值,不過get方法在遭遇到空的Optional對(duì)象時(shí)也會(huì)拋出異常,所以不按照約定的方式使用它,又會(huì)讓我們?cè)俣认萑胗蒼ull引起的代碼維護(hù)的夢(mèng)魘。2.使用 map 從 Optional 對(duì)象中提取和轉(zhuǎn)換值
比如,你可能想要從insurance公司對(duì)象中提取公司的名稱。提取名稱之前,你需要檢查insurance對(duì)象是否為null,代碼如下所示:
String name = null; if(insurance != null){ name = insurance.getName(); }
用Optional實(shí)現(xiàn):
OptionaloptInsurance = Optional.ofNullable(insurance); Optional name = optInsurance.map(Insurance::getName);
原理示意:
OptionaloptPerson = Optional.of(person); Optional name = optPerson.map(Person::getCar) //編譯無法通過 .map(Car::getInsurance) .map(Insurance::getName);
不幸的是,這段代碼無法通過編譯。為什么呢?optPerson是Optional
正確做法:
public String getCarInsuranceName(Optionalperson) { return person.flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) //Insurance::getName返回的是String類型,不是Optional //返回的Optional可能是兩種情況:如果調(diào)用鏈上的任何一個(gè) //方法返回一個(gè)空的Optional,那么結(jié)果就為空,否則返回的值就是你期望的保險(xiǎn)公司的名稱。 .orElse("Unknown"); }
4. 默認(rèn)行為及解引用 Optional 對(duì)象在域模型中使用Optional,以及為什么它們無法序列化
由于Optional類設(shè)計(jì)時(shí)就沒特別考慮將其作為類的字段使用,所以它也并未實(shí)現(xiàn)Serializable接口。
如果你一定要實(shí)現(xiàn)序列化的域模型,作為替代方案,我們建議你像下面這個(gè)例子那樣,提供一個(gè)能訪問聲明為Optional、變量值可能缺失的接口,代碼清單如下:public class Person { private Car car; public OptionalgetCarAsOptional() { return Optional.ofNullable(car); } }
Optional類提供了多種方法讀取Optional實(shí)例中的變量值。
get()是這些方法中最簡(jiǎn)單但又最不安全的方法。如果變量存在,它直接返回封裝的變量值,否則就拋出一個(gè)NoSuchElementException異常。
orElse(T other)是我們?cè)诖a清單10-5中使用的方法,正如之前提到的,它允許你在Optional對(duì)象不包含值時(shí)提供一個(gè)默認(rèn)值。
orElseGet(Supplier extends T> other)是orElse方法的延遲調(diào)用版,Supplier方法只有在Optional對(duì)象不含值時(shí)才執(zhí)行調(diào)用。如果創(chuàng)建默認(rèn)值是件耗時(shí)費(fèi)力的工作,你應(yīng)該考慮采用這種方式(借此提升程序的性能),或者你需要非常確定某個(gè)方法僅在Optional為空時(shí)才進(jìn)行調(diào)用,也可以考慮該方式(這種情況有嚴(yán)格的限制條件)。
orElseThrow(Supplier extends X> exceptionSupplier)和get方法非常類似,它們?cè)庥鯫ptional對(duì)象為空時(shí)都會(huì)拋出一個(gè)異常,但是使用orElseThrow你可以定制希望拋出的異常類型。
ifPresent(Consumer super T>)讓你能在變量值存在時(shí)執(zhí)行一個(gè)作為參數(shù)傳入的方法,否則就不進(jìn)行任何操作
5.以不解包的方式組合兩個(gè)Optional對(duì)象public Insurance findCheapestInsurance(Person person, Car car) { // 不同的保險(xiǎn)公司提供的查詢服務(wù) // 對(duì)比所有數(shù)據(jù) return cheapestCompany; }
public OptionalnullSafeFindCheapestInsurance( Optional person, Optional car) { return person.flatMap(p -> car.map(c -> findCheapestInsurance(p, c))); }
這段代碼中,你對(duì)第一個(gè)Optional對(duì)象調(diào)用flatMap方法,如果它是個(gè)空值,傳遞給它的Lambda表達(dá)式不會(huì)執(zhí)行,這次調(diào)用會(huì)直接返回一個(gè)空的Optional對(duì)象。反之,如果person對(duì)象存在,這次調(diào)用就會(huì)將其作為函數(shù)Function的輸入,并按照與flatMap方法的約定返回一個(gè)Optional
OptionaloptInsurance = ...; optInsurance.filter(insurance -> "CambridgeInsurance".equals(insurance.getName())) .ifPresent(x -> System.out.println("ok"));
filter方法接受一個(gè)謂詞作為參數(shù)。如果Optional對(duì)象的值存在,并且它符合謂詞的條件,
filter方法就返回其值;否則它就返回一個(gè)空的Optional對(duì)象。
Optional類的方法:
與 Stream對(duì)象一樣,Optional也提供了類似的基礎(chǔ)類型——OptionalInt、OptionalLong以及OptionalDouble,如果Stream對(duì)象包含了大量元素,出于性能的考量,使用基礎(chǔ)類型是不錯(cuò)的選擇,但對(duì)Optional對(duì)象而言,這個(gè)理由就不成立了,因?yàn)镺ptional對(duì)象最多只包含一個(gè)值。我們不推薦大家使用基礎(chǔ)類型的Optional,因?yàn)榛A(chǔ)類型的Optional不支持map、flatMap以及filter方法,而這些卻是Optional類最有用的方法。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/74313.html
摘要:當(dāng)我們希望能界定這二者之間的區(qū)別時(shí),我們將第一種稱為純粹的函數(shù)式編程,后者稱為函數(shù)式編程。函數(shù)式編程我們的準(zhǔn)則是,被稱為函數(shù)式的函數(shù)或方法都只能修改本地變量。另一種觀點(diǎn)支持引用透明的函數(shù)式編程,認(rèn)為方法不應(yīng)該有對(duì)外部可見的對(duì)象修改。 一、實(shí)現(xiàn)和維護(hù)系統(tǒng) 1.共享的可變數(shù)據(jù) 如果一個(gè)方法既不修改它內(nèi)嵌類的狀態(tài),也不修改其他對(duì)象的狀態(tài),使用return返回所有的計(jì)算結(jié)果,那么我們稱其為純粹...
摘要:本文是函數(shù)式編程第三章的讀書筆記,章名為流。正確使用表達(dá)式明確要達(dá)成什么轉(zhuǎn)化,而不是說明如何轉(zhuǎn)化沒有副作用只通過函數(shù)的返回值就能充分理解函數(shù)的全部作用函數(shù)不會(huì)修改程序或外界的狀態(tài)獲取值而不是變量避免使用數(shù)組逃過的追殺,應(yīng)該考慮優(yōu)化邏輯 本文是「Java 8 函數(shù)式編程」第三章的讀書筆記,章名為流。本章主要介紹了外部迭代與內(nèi)部迭代以及常用的高階函數(shù)。 外部迭代與內(nèi)部迭代 外部迭代 過去我...
摘要:第四章引入流一什么是流流是的新成員,它允許你以聲明性方式處理數(shù)據(jù)集合通過查詢語句來表達(dá),而不是臨時(shí)編寫一個(gè)實(shí)現(xiàn)。 第四章 引入流 一、什么是流 流是Java API的新成員,它允許你以聲明性方式處理數(shù)據(jù)集合(通過查詢語句來表達(dá),而不是臨時(shí)編寫一個(gè)實(shí)現(xiàn))。就現(xiàn)在來說,你可以把它們看成遍歷數(shù)據(jù)集的高級(jí)迭代器。此外,流還可以透明地并行處理,你無需寫任何多線程代碼。 下面兩段代碼都是用來返回低...
摘要:重構(gòu)在不改變代碼的外在的行為的前提下對(duì)代碼進(jìn)行修改最大限度的減少錯(cuò)誤的幾率本質(zhì)上,就是代碼寫好之后修改它的設(shè)計(jì)。重構(gòu)可以深入理解代碼并且?guī)椭业?。同時(shí)重構(gòu)可以減少引入的機(jī)率,方便日后擴(kuò)展。平行繼承目的在于消除類之間的重復(fù)代碼。 重構(gòu) (refactoring) 在不改變代碼的外在的行為的前提下 對(duì)代碼進(jìn)行修改最大限度的減少錯(cuò)誤的幾率 本質(zhì)上, 就是代碼寫好之后 修改它的設(shè)計(jì)。 1,書中...
摘要:發(fā)布的對(duì)象內(nèi)部狀態(tài)可能會(huì)破壞封裝性,使程序難以維持不變性條件。不變性線程安全性是不可變對(duì)象的固有屬性之一。可變對(duì)象必須通過安全方式來發(fā)布,并且必須是線程安全的或者有某個(gè)鎖保護(hù)起來。 線程的優(yōu)缺點(diǎn) 線程是系統(tǒng)調(diào)度的基本單位。線程如果使用得當(dāng),可以有效地降低程序的開發(fā)和維護(hù)等成本,同時(shí)提升復(fù)雜應(yīng)用程序的性能。多線程程序可以通過提高處理器資源的利用率來提升系統(tǒng)的吞吐率。與此同時(shí),在線程的使用...
摘要:之前,使用匿名類給蘋果排序的代碼是的,這段代碼看上去并不是那么的清晰明了,使用表達(dá)式改進(jìn)后或者是不得不承認(rèn),代碼看起來跟清晰了。這是由泛型接口內(nèi)部實(shí)現(xiàn)方式造成的。 # Lambda表達(dá)式在《Java8實(shí)戰(zhàn)》中第三章主要講的是Lambda表達(dá)式,在上一章節(jié)的筆記中我們利用了行為參數(shù)化來因?qū)Σ粩嘧兓男枨?,最后我們也使用到了Lambda,通過表達(dá)式為我們簡(jiǎn)化了很多代碼從而極大地提高了我們的...
閱讀 841·2021-09-22 15:18
閱讀 1197·2021-09-09 09:33
閱讀 2766·2019-08-30 10:56
閱讀 1203·2019-08-29 16:30
閱讀 1499·2019-08-29 13:02
閱讀 1471·2019-08-26 13:55
閱讀 1653·2019-08-26 13:41
閱讀 1950·2019-08-26 11:56