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