optional

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實戰html

http://blog.csdn.net/sun_promise/article/details/51362838java

Java8實戰的一個例子程序員

 

1.Optional簡述 

到目前爲止,著名的NullPointerException是致使Java應用程序失敗的最多見緣由。過去,爲了解決空指針異常,Google公司著名的Guava項目引入了Optional類,Guava經過使用檢查空值的方式來防止代碼污染,它鼓勵程序員寫更乾淨的代碼。現在,受到Google Guava的啓發,Optional類已經成爲Java 8類庫的一部分。api


Optional:按照字面英文解釋爲「可選的」 意思,但此處的語義是指某個值可能有也可能沒有(null)promise

Optional 被定義爲一個簡單的容器,其值多是null或者不是null。在Java 8以前通常某個函數應該返回非空對象可是偶爾卻可能返回了null,而在Java 8 之後,不推薦你返回null而是返回Optional。安全

 

Optional英文文檔地址:http://docs.oracle.com/javase/8/docs/api/java/util/Optional.htmloracle

 

2.對 Optional 應用的理解

Java 8借鑑了Scala和Haskell,提供了一個新的Optional模板,能夠用它來封裝可能爲空的引用。但它毫不是終結空指針,更多隻是使API的設計者能夠在代碼層面聲明一個方法可能會返回空值,調用方應該注意這種狀況。所以,這隻對新的API有效,前提是調用者不要讓引用逃逸出封裝類,不然引用可能會在外面被不安全的廢棄掉。app

我的對這個新的特性是又愛又恨。一方面,空指針是一個大問題,只要能解決這個問題的東西筆者都歡迎。但另外一方面,我的對它是否能擔此重任執懷疑的態度。這是因爲使用它須要全公司的集體努力,短時間內很難會有見效。若非大力地推廣使用,極可能會功虧一簣。less

 

3.Optional的優勢

1)顯式的提醒你須要關注null的狀況,對程序員是一種字面上的約束
2)將平時的一些顯式的防護性檢測給標準化了,並提供一些可串聯操做

3)解決null會致使疑惑的概念eclipse

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 異常,咱們常常會寫出這樣的代碼:

 

[java]  view plain  copy
 
  1. Student student = person.find("Lucy");  
  2.         if (student != null) {  
  3.             student.doSomething();  
  4.         }  

使用Optional的代碼寫法:

 

 

[java]  view plain  copy
 
  1. Student student = person.find("Lucy");  
  2.         if (student.isPresent()) {  
  3.             student.get().doSomething();  
  4.         }  
說明:若是isPresent()返回false,說明這是個空對象;不然,咱們就能夠把其中的內容取出來作相應的操做了。
單從代碼量上來講,Optional的代碼量並未減小,甚至比原來的代碼還多。但好在,你絕對不會忘記判空,由於這裏咱們獲得的不是Student類的對象,而是Optional。

 

 

4.3Optional類的主要方法

1) of(T value)

爲非null的值建立一個Optional。

of()方法經過工廠方法建立Optional類。須要注意,建立對象時傳入的參數不能爲null。若是傳入參數爲null,則拋出NullPointerException 。

eg:

 

[java]  view plain  copy
 
  1. //調用工廠方法建立Optional實例  
  2.     Optional<String> myValue = Optional.of("OptionalTest");  
  3.     //傳入參數爲null,拋出NullPointerException.  
  4.     Optional<String> someNull = Optional.of(null);  

 

 

2) ofNullable(T value)

爲指定的值建立一個Optional,若是指定的值爲null,則返回一個空的Optional。

ofNullable與of方法類似,惟一的區別是能夠接受參數爲null的狀況。

eg:

 

[java]  view plain  copy
 
  1. //下面建立了一個不包含任何值的Optional實例  
  2. //eg:值爲'null'  
  3. Optional empty = Optional.ofNullable(null);  

 

 

3) isPresent()

若是值存在返回true,不然返回false。

eg:

 

[java]  view plain  copy
 
  1. //isPresent()方法用來檢查Optional實例中是否包含值  
  2. if (myValue.isPresent()) {  
  3. //在Optional實例內調用get()返回已存在的值  
  4. System.out.println(myValue.get());//輸出OptionalTest }  

 

4) get()

若是Optional有值則將其返回,不然拋出異常 NoSuchElementException。

在上面的示例中,get方法用來獲得Optional實例中的值。下面是一個拋出NoSuchElementException的示例:

eg:

 

[java]  view plain  copy
 
  1. //執行下面的代碼會輸出:No value present   
  2.         try {  
  3.           //在空的Optional實例上調用get(),拋出NoSuchElementException  
  4.           System.out.println(empty.get());  
  5.         } catch (NoSuchElementException ex) {  
  6.           System.out.println(ex.getMessage());  
  7.         }  

 

5) ifPresent(Consumer<? super T> consumer)

若是Optional實例有值則爲其調用consumer,不然不作處理。

要理解ifPresent()方法,首先須要瞭解Consumer類。簡單地說,Consumer類包含一個抽象方法。該抽象方法對傳入的值進行處理,但沒有返回值。Java8支持不用接口直接經過lambda表達式傳入參數。

若是Optional實例有值,調用ifPresent()能夠接受接口段或lambda表達式。

eg:

 

[java]  view plain  copy
 
  1. //ifPresent()方法接受lambda表達式做爲參數。  
  2.         //lambda表達式對Optional的值調用consumer進行處理。  
  3.         myValue.ifPresent((value) -> {  
  4.           System.out.println("The length of the value is: " + value.length());  
  5.         });  

 

 

6) orElse(T other)

若是有值則將其返回,不然返回指定的其它值。
若是Optional實例有值則將其返回,不然返回orElse方法傳入的參數。即:參數other爲默認返回值

eg:

 

[java]  view plain  copy
 
  1. //若是值不爲null,orElse方法返回Optional實例的值。  
  2.         //若是爲null,返回傳入的消息。  
  3.         //輸出:There is no value present!  
  4.         System.out.println(empty.orElse("There is no value present!"));  
  5.         //輸出:OptionalTest  
  6.         System.out.println(myValue.orElse("There is some value!"));  

 

 

7) orElseGet(Supplier<? extends T> other)

orElseGet與orElse方法相似,區別在於獲得的默認值。orElse方法將傳入的參數字符串做爲默認值,orElseGet方法能夠接受Supplier接口的實現用來生成默認值。

eg:

 

[java]  view plain  copy
 
  1. //orElseGet能夠接受一個lambda表達式生成默認值。  
  2.         //輸出:Default Value  
  3.         System.out.println(empty.orElseGet(() -> "Default Value"));  
  4.         //輸出:OptionalTest  
  5.         System.out.println(myValue.orElseGet(() -> "Default Value"));  

 

 

8) orElseThrow(Supplier<? extends X> exceptionSupplier)

若是有值則將其返回,不然拋出supplier接口建立的異常。
在orElseGet()方法中,咱們傳入一個Supplier接口。然而,在orElseThrow中咱們能夠傳入一個lambda表達式或方法,若是值不存在就拋出異常。

eg:

 

[java]  view plain  copy
 
  1. try {  
  2.           //orElseThrow與orElse方法相似。與返回默認值不一樣,  
  3.           //orElseThrow會拋出lambda表達式或方法生成的異常   
  4.            
  5.           empty.orElseThrow(ValueAbsentException::new);  
  6.         } catch (Throwable ex) {  
  7.           //輸出: No value present in the Optional instance  
  8.           System.out.println(ex.getMessage());  
  9.         }  

 

[java]  view plain  copy
 
  1. class ValueAbsentException extends Throwable {  
  2.    
  3.   public ValueAbsentException() {  
  4.     super();  
  5.   }  
  6.    
  7.   public ValueAbsentException(String msg) {  
  8.     super(msg);  
  9.   }  
  10.    
  11.   @Override  
  12.   public String getMessage() {  
  13.     return "No value present in the Optional instance";  
  14.   }  
  15. }  


 

 

9) map(Function<? super T,? extends U> mapper)

若是有值,則對其執行調用mapping函數獲得返回值。若是返回值不爲null,則建立包含mapping返回值的Optional做爲map方法返回值,不然返回空Optional。
map方法用來對Optional實例的值執行一系列操做。經過一組實現了Function接口的lambda表達式傳入操做。

eg:

 

[java]  view plain  copy
 
  1. //map方法執行傳入的lambda表達式參數對Optional實例的值進行修改。  
  2. //爲Lambda表達式的返回值建立新的Optional實例做爲map方法的返回值。  
  3. Optional<String> upperName = myValue.map((value) -> value.toUpperCase());  
  4. 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重寫的示例

 

[java]  view plain  copy
 
  1. //map方法中的lambda表達式返回值能夠是任意類型,在map函數返回以前會包裝爲Optional。   
  2. //但flatMap方法中的lambda表達式返回值必須是Optionl實例。   
  3. upperName = myValue.flatMap((value) -> Optional.of(value.toUpperCase()));  
  4. System.out.println(upperName.orElse("No value found"));  

 

11) filter(Predicate<? super T> predicate)

若是有值而且知足斷言條件返回包含該值的Optional,不然返回空Optional。


filter個方法經過傳入限定條件對Optional實例的值進行過濾。

對於filter函數咱們能夠傳入實現了Predicate接口的lambda表達式。

eg:

 

[java]  view plain  copy
 
  1. //filter方法檢查給定的Option值是否知足某些條件。  
  2.     //若是知足則返回同一個Option實例,不然返回空Optional。  
  3.     Optional<String> longName = myValue.filter((value) -> value.length() > 6);  
  4.     System.out.println(longName.orElse("The name is less than 6 characters"));//輸出OptionalTest  
  5.        
  6.     //另外一個例子是Optional值不知足filter指定的條件。  
  7.     Optional<String> anotherName = Optional.of("Test");  
  8.     Optional<String> shortName = anotherName.filter((value) -> value.length() > 6);  
  9.     //輸出:name長度不足6字符  
  10.     System.out.println(shortName.orElse("The name is less than 6 characters"));  


 

12) empty()

返回一個空Optional實例。

eg:

 

[java]  view plain  copy
 
  1. 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:

 

[java]  view plain  copy
 
  1. Optional<String> o;  
  2. o.map((value)->Optional.of(value)) //返回的類型是Optional<Optional<String>>  
  3. o.flatMap((value)->Optional.of(value)) //返回的類型是Optional<String>  

 

4.5 Optional應用示例:

Note:測試的時候最好是新建一個java項目(或者直接用eclipse測試),由於Android項目目前不徹底支持java8的新特性,須要配置不少東西,也同樣容易出現各類問題。

 

[java]  view plain  copy
 
  1. import java.util.NoSuchElementException;  
  2. import java.util.Optional;  
  3.   
  4. public class OptionalTest {  
  5.   
  6.     public static void main(String[] args) {  
  7.          // 建立Optional  
  8.         String mayBeNull = null;  
  9.         Optional<String> opt1 = Optional.of(" Hello! ");  
  10.         Optional<String> opt2 = Optional.ofNullable(mayBeNull);  
  11.         Optional<String> opt3 = Optional.empty();  
  12.         opt1.ifPresent(System.out::println); // " Hello! "  
  13.         opt2.ifPresent(System.out::println);  
  14.         opt3.ifPresent(System.out::println);  
  15.   
  16.         //方法測試示例  
  17.         ofTest();  
  18.         ofNullableTest();  
  19.         isPresentTest();  
  20.         ifPresentTest();  
  21.         orElseTest();  
  22.         orElseGetTest();  
  23.         mapTest();  
  24.         flatMapTest();  
  25.         filterTest();  
  26.   
  27.     }  
  28.       
  29.     /** 
  30.      * of後面接給optional設置的值 可是不能爲空 若是爲空會報空指針異常 
  31.      */  
  32.     public static void ofTest() {  
  33.         Optional<String> optional = Optional.of("123");  
  34.         System.out.println(optional.get());  
  35.         try {  
  36.             optional = Optional.of(null);  
  37.             System.out.println("null值--"+optional.get());  //get方法是獲取optional的值 類型取決於聲明的時候  
  38.         } catch (NullPointerException e) {  
  39.             System.out.println("空指針異常");  
  40.         }  
  41.     }  
  42.   
  43.     /** 
  44.      * ofNullable 和of相似 可是ofNullable能夠設置null值  若是是Null值得話取值會報NoSuchElementException 異常 
  45.      */  
  46.     public static void ofNullableTest() {  
  47.         Optional<String> optional = Optional.ofNullable("123");  
  48.         System.out.println(optional.get());  
  49.         try {  
  50.             optional = Optional.ofNullable(null);  
  51.             System.out.println("null值---"+optional.get());  
  52.         } catch (NoSuchElementException e) {  
  53.             System.out.println("NoSuchElementException 異常");  
  54.         }  
  55.     }  
  56.   
  57.     /** 
  58.      * ifPresent用來判斷optional中有沒有值存在 若是有則爲真 
  59.      */  
  60.     public static void isPresentTest() {  
  61.         Optional<String> optional = Optional.ofNullable(null);  
  62.         if (optional.isPresent()) {  
  63.             System.out.println(optional.get());  
  64.         } else {  
  65.             System.out.println("值爲空");  
  66.         }  
  67.     }  
  68.   
  69.     /** 
  70.      * ifPresent和isPresent相似 只不過它支持λ表達式 
  71.      */  
  72.     public static void ifPresentTest() {  
  73.         Optional<String> optional = Optional.ofNullable("123");  
  74.         optional.ifPresent(var -> {  
  75.             System.out.println(var);  
  76.         });  
  77.     }  
  78.   
  79.     /** 
  80.      * orElse方法,若是值爲空的話會用參數中的值去替換 即設置默認值 
  81.      */  
  82.     public static void orElseTest() {  
  83.         Optional<String> optional = Optional.ofNullable("123");  
  84.         System.out.println(optional.orElse("有沒有"));  
  85.         optional = Optional.ofNullable(null);  
  86.         System.out.println(optional.orElse("有沒有000"));  
  87.     }  
  88.   
  89.     /** 
  90.      * orElseGet方法 和orElse相似 不過此方法接受Supplier接口的實現用來生成默認值 
  91.      */  
  92.     public static void orElseGetTest() {  
  93.         Optional<String> optional = Optional.ofNullable("123");  
  94.         System.out.println(optional.orElseGet(() -> "123456"));  
  95.         optional = Optional.ofNullable(null);  
  96.         System.out.println(optional.orElseGet(() -> "1234567"));  
  97.     }  
  98.   
  99.     /** 
  100.      * map方法  若是有值則會對值進行mapping中的處理 處理結果存在則建立並返回Optional類型的結果 不然返回空 
  101.      */  
  102.     public static void mapTest() {  
  103.         Optional<String> optional = Optional.ofNullable("abc");  
  104.         System.out.println(optional.map(var -> var.toUpperCase()).get());  
  105.     }  
  106.   
  107.     /** 
  108.      * flatMap和map相似 只不過mapping中必須返回Option類型的數據 
  109.      */  
  110.     public static void flatMapTest() {  
  111.         Optional<String> optional = Optional.ofNullable("abc");  
  112.         System.out.println(optional.flatMap(var -> Optional.of(var.toUpperCase())).get());  
  113.     }  
  114.   
  115.     /** 
  116.      * filter對optional進行過濾,mapping中爲過濾的條件  若是不知足條件 返回一個爲空的Optional 
  117.      */  
  118.     public static void filterTest() {  
  119.         try {  
  120.             Optional<String> optional = Optional.ofNullable("一二三四五六七八");  
  121.             System.out.println(optional.filter(var -> var.length() > 6).get());  
  122.             System.out.println(optional.filter(var -> var.length() < 6).get());  
  123.         } catch (NoSuchElementException e) {  
  124.             System.out.println("optional的值爲空");  
  125.         }  
  126.     }  
  127.   
  128. }  
相關文章
相關標籤/搜索