# Optional 干掉空指針
## 簡介
* 空指針異常是導致Java應用程序失敗的最常見原因。
* 為了解決空指針異常更加優雅,Java8 提供了`Optional`類庫。
* `Optional`實際上是個容器:它可以保存類型T的值,或者僅僅保存null。
* `Optional`提供很多有用的方法,這樣我們就不用顯式進行空值檢測。
## 代碼示例
1. `Optional.of()`或者`Optional.ofNullable()`:創建`Optional`對象,差別在于`of`不允許參數是`null`,而`ofNullable`則無限制。
~~~
// 參數不能是null
Optional optional1 = Optional.of(1);
// 參數可以是null
Optional optional2 = Optional.ofNullable(null);
// 參數可以是非null
Optional optional3 = Optional.ofNullable(2);
~~~
2. `Optional.empty()`:所有null包裝成的`Optional`對象
~~~
Optional optional1 = Optional.ofNullable(null);
Optional optional2 = Optional.ofNullable(null);
System.out.println(optional1 == optional2);// true
System.out.println(optional1 == Optional.empty());// true
Object o1 = Optional.empty();
Object o2 = Optional.empty();
System.out.println(o1 == o2);// true
~~~
3. `isPresent()`:判斷值是否存在
~~~
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
// isPresent判斷值是否存在
System.out.println(optional1.isPresent() == true);
System.out.println(optional2.isPresent() == false);
~~~
4. `ifPresent(Consumer consumer)`:如果option對象保存的值不是null,則調用consumer對象,否則不調用
~~~
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
// 如果不是null,調用Consumer
optional1.ifPresent(new Consumer<Integer>() {
@Override
public void accept(Integer t) {
System.out.println("value is " + t);
}
});
// null,不調用Consumer
optional2.ifPresent(new Consumer<Integer>() {
@Override
public void accept(Integer t) {
System.out.println("value is " + t);
}
});
~~~
5. `orElse(value)`:如果optional對象保存的值不是`null`,則返回原來的值,否則返回`value`
~~~
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
// orElse
System.out.println(optional1.orElse(1000) == 1);// true
System.out.println(optional2.orElse(1000) == 1000);// true
~~~
6. `orElseGet(Supplier supplier)`:功能與`orElse`一樣,只不過`orElseGet`參數是一個對象
~~~
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
System.out.println(optional1.orElseGet(() -> 1000) == 1);//true
System.out.println(optional2.orElseGet(() -> 1000) == 1000);//true
~~~
7. `orElseThrow()`:值不存在則拋出異常,存在則什么不做,有點類似`Guava`的`Precoditions`
~~~
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
optional1.orElseThrow(() -> {
throw new IllegalStateException();
});
try {
optional2.orElseThrow(() -> {
throw new IllegalStateException();
});
} catch (IllegalStateException e) {
e.printStackTrace();
}
~~~
8. `filter(Predicate)`:判斷`Optional`對象中保存的值是否滿足`Predicate`,并返回新的`Optional`。
~~~
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
Optional<Integer> filter1 = optional1.filter((a) -> a == null);
Optional<Integer> filter2 = optional1.filter((a) -> a == 1);
Optional<Integer> filter3 = optional2.filter((a) -> a == null);
System.out.println(filter1.isPresent());// false
System.out.println(filter2.isPresent());// true
System.out.println(filter2.get().intValue() == 1);// true
System.out.println(filter3.isPresent());// false
~~~
9. `map(Function)`:對`Optional`中保存的值進行函數運算,并返回新的`Optional`(可以是任何類型)
~~~
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
Optional<String> str1Optional = optional1.map((a) -> "key" + a);
Optional<String> str2Optional = optional2.map((a) -> "key" + a);
System.out.println(str1Optional.get());// key1
System.out.println(str2Optional.isPresent());// false
~~~
10.`flatMap()`:功能與`map()`相似,差別請看如下代碼。`flatMap`方法與`map`方法類似,區別在于`mapping`函數的返回值不同。`map`方法的`mapping`函數返回值可以是任何類型`T`,而`flatMap`方法的`mapping`函數必須是`Optional`。
~~~
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Optional<String>> str1Optional = optional1.map((a) -> Optional.of("key" + a));
Optional<String> str2Optional = optional1.flatMap((a) -> Optional.of("key" + a));
System.out.println(str1Optional.get().get());// key1
System.out.println(str2Optional.get());// key1
~~~
## Optional類的方法

- 序
- 快速開始
- 環境要求
- 環境準備
- 工程導入
- 工程運行
- 技術基礎
- Java8
- Lambda
- Lambda 受檢異常處理
- Stream 簡介
- Stream API 一覽
- Stream API(上)
- Stream API(下)
- Optional 干掉空指針
- 函數式接口
- 新的日期 API
- Lombok
- SpringMVC
- Swagger
- Mybaties
- Mybaties-plus
- 開發初探
- 新建微服務工程
- 第一個API
- API鑒權
- API響應結果
- Redis 緩存
- 第一個CRUD
- 建表
- 建Entity
- 建Service和Mapper
- 新增API
- 修改API
- 刪除API
- 查詢API
- 單條查詢
- 多條查詢
- 分頁
- 微服務遠程調用
- 聲明式服務調用Feign
- 熔斷機制 Hystrix
- 開發進階