public class Test { public static void main(String[] args) { People people = new People(); Optional<People> p = Optional.ofNullable(people); String name = p.flatMap(People::getCar).flatMap(Car::getInsurence).map(Insurence::getName).orElse("string"); } } class People{ private Optional<Car> car; public Optional<Car> getCar() { return car; } } class Car{ private Optional<Insurence> insurence; public Optional<Insurence> getInsurence() { return insurence; } } class Insurence{ String name; public String getName() { return name; } }
這篇寫的很好,另外參考Java8實戰
http://blog.csdn.net/sun_promise/article/details/51362838
Java8實戰的一個例子
1.Optional簡述
到目前為止,著名的NullPointerException是導致Java應用程序失敗的最常見原因。過去,為了解決空指針異常,Google公司著名的Guava項目引入了Optional類,Guava通過使用檢查空值的方式來防止代碼污染,它鼓勵程序員寫更干凈的代碼。如今,受到Google Guava的啟發,Optional類已經成為Java 8類庫的一部分。
Optional:按照字面英文解釋為“可選的” 意思,但此處的語義是指某個值可能有也可能沒有(null)。Optional 被定義為一個簡單的容器,其值可能是null或者不是null。在Java 8之前一般某個函數應該返回非空對象但是偶爾卻可能返回了null,而在Java 8 以后,不推薦你返回null而是返回Optional。
Optional英文文檔地址:http://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
2.對 Optional 應用的理解
Java 8借鑒了Scala和Haskell,提供了一個新的Optional模板,可以用它來封裝可能為空的引用。但它絕不是終結空指針,更多只是使API的設計者可以在代碼層面聲明一個方法可能會返回空值,調用方應該注意這種情況。因此,這只對新的API有效,前提是調用者不要讓引用逃逸出封裝類,否則引用可能會在外面被不安全的廢棄掉。
個人對這個新的特性是又愛又恨。一方面,空指針是一個大問題,只要能解決這個問題的東西筆者都歡迎。但另一方面,個人對它是否能擔此重任執懷疑的態度。這是由於使用它需要全公司的集體努力,短期內很難會有見效。若非大力地推廣使用,很可能會功虧一簣。
3.Optional的優點
1)顯式的提醒你需要關注null的情況,對程序員是一種字面上的約束
2)將平時的一些顯式的防御性檢測給標准化了,並提供一些可串聯操作
3)解決null會導致疑惑的概念
eg:Map里面的key==null的情況,以及value==null的情況
4.Optional類
4.1 Optional類的官方描述
A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.
(這是一個可以為null的容器對象。如果值存在則isPresent()方法會返回true,調用get()方法會返回該對象。)
4.2 Optional的簡單使用
Optional類的包名:java.util.Optional<T>
為了防止拋出java.lang.NullPointerException 異常,我們經常會寫出這樣的代碼:
- Student student = person.find("Lucy");
- if (student != null) {
- student.doSomething();
- }
使用Optional的代碼寫法:
說明:如果isPresent()返回false,說明這是個空對象;否則,我們就可以把其中的內容取出來做相應的操作了。
- Student student = person.find("Lucy");
- if (student.isPresent()) {
- student.get().doSomething();
- }
單從代碼量上來說,Optional的代碼量並未減少,甚至比原來的代碼還多。但好在,你絕對不會忘記判空,因為這里我們得到的不是Student類的對象,而是Optional。
4.3Optional類的主要方法
1) of(T value)
為非null的值創建一個Optional。
of()方法通過工廠方法創建Optional類。需要注意,創建對象時傳入的參數不能為null。如果傳入參數為null,則拋出NullPointerException 。
eg:
- //調用工廠方法創建Optional實例
- Optional<String> myValue = Optional.of("OptionalTest");
- //傳入參數為null,拋出NullPointerException.
- Optional<String> someNull = Optional.of(null);
2) ofNullable(T value)
為指定的值創建一個Optional,如果指定的值為null,則返回一個空的Optional。ofNullable與of方法相似,唯一的區別是可以接受參數為null的情況。
eg:
- //下面創建了一個不包含任何值的Optional實例
- //eg:值為'null'
- Optional empty = Optional.ofNullable(null);
3) isPresent()
如果值存在返回true,否則返回false。
eg:
- //isPresent()方法用來檢查Optional實例中是否包含值
- if (myValue.isPresent()) {
- //在Optional實例內調用get()返回已存在的值
- System.out.println(myValue.get());//輸出OptionalTest }
4) get()
如果Optional有值則將其返回,否則拋出異常 NoSuchElementException。
在上面的示例中,get方法用來得到Optional實例中的值。下面是一個拋出NoSuchElementException的示例:
eg:
- //執行下面的代碼會輸出:No value present
- try {
- //在空的Optional實例上調用get(),拋出NoSuchElementException
- System.out.println(empty.get());
- } catch (NoSuchElementException ex) {
- System.out.println(ex.getMessage());
- }
5) ifPresent(Consumer<? super T> consumer)
如果Optional實例有值則為其調用consumer,否則不做處理。
要理解ifPresent()方法,首先需要了解Consumer類。簡單地說,Consumer類包含一個抽象方法。該抽象方法對傳入的值進行處理,但沒有返回值。Java8支持不用接口直接通過lambda表達式傳入參數。
如果Optional實例有值,調用ifPresent()可以接受接口段或lambda表達式。
eg:
- //ifPresent()方法接受lambda表達式作為參數。
- //lambda表達式對Optional的值調用consumer進行處理。
- myValue.ifPresent((value) -> {
- System.out.println("The length of the value is: " + value.length());
- });
6) orElse(T other)
如果有值則將其返回,否則返回指定的其它值。
如果Optional實例有值則將其返回,否則返回orElse方法傳入的參數。即:參數other為默認返回值eg:
- //如果值不為null,orElse方法返回Optional實例的值。
- //如果為null,返回傳入的消息。
- //輸出:There is no value present!
- System.out.println(empty.orElse("There is no value present!"));
- //輸出:OptionalTest
- System.out.println(myValue.orElse("There is some value!"));
7) orElseGet(Supplier<? extends T> other)
orElseGet與orElse方法類似,區別在於得到的默認值。orElse方法將傳入的參數字符串作為默認值,orElseGet方法可以接受Supplier接口的實現用來生成默認值。
eg:
- //orElseGet可以接受一個lambda表達式生成默認值。
- //輸出:Default Value
- System.out.println(empty.orElseGet(() -> "Default Value"));
- //輸出:OptionalTest
- System.out.println(myValue.orElseGet(() -> "Default Value"));
8) orElseThrow(Supplier<? extends X> exceptionSupplier)
如果有值則將其返回,否則拋出supplier接口創建的異常。
在orElseGet()方法中,我們傳入一個Supplier接口。然而,在orElseThrow中我們可以傳入一個lambda表達式或方法,如果值不存在就拋出異常。eg:
- try {
- //orElseThrow與orElse方法類似。與返回默認值不同,
- //orElseThrow會拋出lambda表達式或方法生成的異常
- empty.orElseThrow(ValueAbsentException::new);
- } catch (Throwable ex) {
- //輸出: No value present in the Optional instance
- System.out.println(ex.getMessage());
- }
- class ValueAbsentException extends Throwable {
- public ValueAbsentException() {
- super();
- }
- public ValueAbsentException(String msg) {
- super(msg);
- }
- @Override
- public String getMessage() {
- return "No value present in the Optional instance";
- }
- }
9) map(Function<? super T,? extends U> mapper)
如果有值,則對其執行調用mapping函數得到返回值。如果返回值不為null,則創建包含mapping返回值的Optional作為map方法返回值,否則返回空Optional。
map方法用來對Optional實例的值執行一系列操作。通過一組實現了Function接口的lambda表達式傳入操作。eg:
- //map方法執行傳入的lambda表達式參數對Optional實例的值進行修改。
- //為Lambda表達式的返回值創建新的Optional實例作為map方法的返回值。
- Optional<String> upperName = myValue.map((value) -> value.toUpperCase());
- System.out.println(upperName.orElse("No value found"));
10) flatMap(Function<? super T,Optional<U>> mapper)
如果有值,為其執行mapping函數返回Optional類型返回值,否則返回空Optional。flatMap與map(Funtion)方法類似,區別在於flatMap中的mapper返回值必須是Optional。調用結束時,flatMap不會對結果用Optional封裝。
flatMap方法與map方法類似,區別在於mapping函數的返回值不同。map方法的mapping函數返回值可以是任何類型T,而flatMap方法的mapping函數必須是Optional。eg:
下面參照map函數,使用flatMap重寫的示例
- //map方法中的lambda表達式返回值可以是任意類型,在map函數返回之前會包裝為Optional。
- //但flatMap方法中的lambda表達式返回值必須是Optionl實例。
- upperName = myValue.flatMap((value) -> Optional.of(value.toUpperCase()));
- System.out.println(upperName.orElse("No value found"));
11) filter(Predicate<? super T> predicate)
如果有值並且滿足斷言條件返回包含該值的Optional,否則返回空Optional。
filter個方法通過傳入限定條件對Optional實例的值進行過濾。對於filter函數我們可以傳入實現了Predicate接口的lambda表達式。
eg:
- //filter方法檢查給定的Option值是否滿足某些條件。
- //如果滿足則返回同一個Option實例,否則返回空Optional。
- Optional<String> longName = myValue.filter((value) -> value.length() > 6);
- System.out.println(longName.orElse("The name is less than 6 characters"));//輸出OptionalTest
- //另一個例子是Optional值不滿足filter指定的條件。
- Optional<String> anotherName = Optional.of("Test");
- Optional<String> shortName = anotherName.filter((value) -> value.length() > 6);
- //輸出:name長度不足6字符
- System.out.println(shortName.orElse("The name is less than 6 characters"));
12) empty()
返回一個空Optional實例。
eg:
- Optional.<String>empty(); // 返回一個空Optional<String>
Note:
Optional有這么多方法,那Optional的初衷是什么?而且Optional也是一個對象,所以它本身也有可能是null,這可如何是好。所以,個人認為,Optional比較適用的地方是作為返回值,這樣可以給使用者一個善意的提醒。
4.4 map 與 flatMap 的區別
map(mapper) 與 flatMap(mapper) 功能上基本是一樣的,只是最后的返回值不一樣。map(mapper)方法中的mapper可以返回任意類型,但是flatMap(mapper)方法中的mapper只能返回Optional類型。
如果mapper返回結果result的不是null,那么map就會返回一個Optional,但是 flatMap不會對result進行任何包裝。
eg:
- Optional<String> o;
- o.map((value)->Optional.of(value)) //返回的類型是Optional<Optional<String>>
- o.flatMap((value)->Optional.of(value)) //返回的類型是Optional<String>
4.5 Optional應用示例:
Note:測試的時候最好是新建一個java項目(或者直接用eclipse測試),因為Android項目目前不完全支持java8的新特性,需要配置很多東西,也一樣容易出現各種問題。
- import java.util.NoSuchElementException;
- import java.util.Optional;
- public class OptionalTest {
- public static void main(String[] args) {
- // 創建Optional
- String mayBeNull = null;
- Optional<String> opt1 = Optional.of(" Hello! ");
- Optional<String> opt2 = Optional.ofNullable(mayBeNull);
- Optional<String> opt3 = Optional.empty();
- opt1.ifPresent(System.out::println); // " Hello! "
- opt2.ifPresent(System.out::println);
- opt3.ifPresent(System.out::println);
- //方法測試示例
- ofTest();
- ofNullableTest();
- isPresentTest();
- ifPresentTest();
- orElseTest();
- orElseGetTest();
- mapTest();
- flatMapTest();
- filterTest();
- }
- /**
- * of后面接給optional設置的值 但是不能為空 如果為空會報空指針異常
- */
- public static void ofTest() {
- Optional<String> optional = Optional.of("123");
- System.out.println(optional.get());
- try {
- optional = Optional.of(null);
- System.out.println("null值--"+optional.get()); //get方法是獲取optional的值 類型取決於聲明的時候
- } catch (NullPointerException e) {
- System.out.println("空指針異常");
- }
- }
- /**
- * ofNullable 和of類似 但是ofNullable可以設置null值 如果是Null值得話取值會報NoSuchElementException 異常
- */
- public static void ofNullableTest() {
- Optional<String> optional = Optional.ofNullable("123");
- System.out.println(optional.get());
- try {
- optional = Optional.ofNullable(null);
- System.out.println("null值---"+optional.get());
- } catch (NoSuchElementException e) {
- System.out.println("NoSuchElementException 異常");
- }
- }
- /**
- * ifPresent用來判斷optional中有沒有值存在 如果有則為真
- */
- public static void isPresentTest() {
- Optional<String> optional = Optional.ofNullable(null);
- if (optional.isPresent()) {
- System.out.println(optional.get());
- } else {
- System.out.println("值為空");
- }
- }
- /**
- * ifPresent和isPresent類似 只不過它支持λ表達式
- */
- public static void ifPresentTest() {
- Optional<String> optional = Optional.ofNullable("123");
- optional.ifPresent(var -> {
- System.out.println(var);
- });
- }
- /**
- * orElse方法,如果值為空的話會用參數中的值去替換 即設置默認值
- */
- public static void orElseTest() {
- Optional<String> optional = Optional.ofNullable("123");
- System.out.println(optional.orElse("有沒有"));
- optional = Optional.ofNullable(null);
- System.out.println(optional.orElse("有沒有000"));
- }
- /**
- * orElseGet方法 和orElse類似 不過此方法接受Supplier接口的實現用來生成默認值
- */
- public static void orElseGetTest() {
- Optional<String> optional = Optional.ofNullable("123");
- System.out.println(optional.orElseGet(() -> "123456"));
- optional = Optional.ofNullable(null);
- System.out.println(optional.orElseGet(() -> "1234567"));
- }
- /**
- * map方法 如果有值則會對值進行mapping中的處理 處理結果存在則創建並返回Optional類型的結果 否則返回空
- */
- public static void mapTest() {
- Optional<String> optional = Optional.ofNullable("abc");
- System.out.println(optional.map(var -> var.toUpperCase()).get());
- }
- /**
- * flatMap和map類似 只不過mapping中必須返回Option類型的數據
- */
- public static void flatMapTest() {
- Optional<String> optional = Optional.ofNullable("abc");
- System.out.println(optional.flatMap(var -> Optional.of(var.toUpperCase())).get());
- }
- /**
- * filter對optional進行過濾,mapping中為過濾的條件 如果不滿足條件 返回一個為空的Optional
- */
- public static void filterTest() {
- try {
- Optional<String> optional = Optional.ofNullable("一二三四五六七八");
- System.out.println(optional.filter(var -> var.length() > 6).get());
- System.out.println(optional.filter(var -> var.length() < 6).get());
- } catch (NoSuchElementException e) {
- System.out.println("optional的值為空");
- }
- }
- }