Java 8中引入了一個新的類java.util.Optional<T>。變量存在時,Optional類只是對類簡單封裝。變量不存在時,缺失的值會被建模成一個「空」
的Optional對象,由方法Optional.empty()返回。java
正如前文已經提到,你能夠經過靜態工廠方法Optional.empty,建立一個空的Optional對象:安全
Optional<Car> optCar = Optional.empty();
你還可使用靜態工廠方法Optional.of,依據一個非空值建立一個Optional對象:函數
Optional<Car> optCar = Optional.of(car);
若是car是一個null,這段代碼會當即拋出一個NullPointerException,而不是等到你試圖訪問car的屬性值時才返回一個錯誤。性能
最後,使用靜態工廠方法Optional.ofNullable,你能夠建立一個容許null值的Optional對象:spa
Optional<Car> optCar = Optional.ofNullable(car);
若是car是null,那麼獲得的Optional對象就是個空對象。設計
Optional提供了一個 get方法用於獲取Optional變量中的值,不過get方法在遭遇到空的Optional對象時也會拋出異常,因此不按照約定的方式使用它,又會讓咱們再度陷入由null引發的代碼維護的夢魘。
好比,你可能想要從insurance公司對象中提取公司的名稱。提取名稱以前,你須要檢查insurance對象是否爲null,代碼以下所示:code
String name = null; if(insurance != null){ name = insurance.getName(); }
用Optional實現:對象
Optional<Insurance> optInsurance = Optional.ofNullable(insurance); Optional<String> name = optInsurance.map(Insurance::getName);
原理示意:接口
Optional<Person> optPerson = Optional.of(person); Optional<String> name = optPerson.map(Person::getCar) //編譯沒法經過 .map(Car::getInsurance) .map(Insurance::getName);
不幸的是,這段代碼沒法經過編譯。爲何呢?optPerson是Optional<Person>類型的變量, 調用map方法應該沒有問題。但getCar返回的是一個Optional<Car>類型的對象,這意味着map操做的結果是一個Optional<Optional<Car>>類型的對象。所以,它對getInsurance的調用是非法的,由於最外層的optional對象包含了另外一個optional對象的值,而它固然不會支持getInsurance方法。
正確作法:圖片
public String getCarInsuranceName(Optional<Person> person) { return person.flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) //Insurance::getName返回的是String類型,不是Optional //返回的Optional多是兩種狀況:若是調用鏈上的任何一個 //方法返回一個空的Optional,那麼結果就爲空,不然返回的值就是你指望的保險公司的名稱。 .orElse("Unknown"); }
在域模型中使用Optional,以及爲何它們沒法序列化
因爲Optional類設計時就沒特別考慮將其做爲類的字段使用,因此它也並未實現Serializable接口。
若是你必定要實現序列化的域模型,做爲替代方案,咱們建議你像下面這個例子那樣,提供一個能訪問聲明爲Optional、變量值可能缺失的接口,代碼清單以下:public class Person { private Car car; public Optional<Car> getCarAsOptional() { return Optional.ofNullable(car); } }
Optional類提供了多種方法讀取Optional實例中的變量值。
public Insurance findCheapestInsurance(Person person, Car car) { // 不一樣的保險公司提供的查詢服務 // 對比全部數據 return cheapestCompany; }
public Optional<Insurance> nullSafeFindCheapestInsurance( Optional<Person> person, Optional<Car> car) { return person.flatMap(p -> car.map(c -> findCheapestInsurance(p, c))); }
這段代碼中,你對第一個Optional對象調用flatMap方法,若是它是個空值,傳遞給它的Lambda表達式不會執行,此次調用會直接返回一個空的Optional對象。反之,若是person對象存在,此次調用就會將其做爲函數Function的輸入,並按照與flatMap方法的約定返回一個Optional<Insurance>對象。這個函數的函數體會對第二個Optional對象執行map操做,若是第二個對象不包含car,函數Function就返回一個空的Optional對象,整個nullSafeFindCheapestInsuranc方法的返回值也是一個空的Optional對象。最後,若是person和car對象都存在,做爲參數傳遞給map方法的Lambda表達式可以使用這兩個值安全地調用原始的findCheapestInsurance方法,完成指望的操做。
Optional<Insurance> optInsurance = ...; 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類最有用的方法。