## 簡介
* 空指針異常是導致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類的方法
| 方法 | 描述 |
|:-----:|:-------|
| `empty` | 返回一個空的 Optional 實例 |
| `filter` | 如果值存在并且滿足提供的斷言, 就返回包含該值的 Optional 對象;否則返回一個空的 Optional 對象 |
| `map` | 如果值存在,就對該值執行提供的 mapping 函數調用 |
| `flatMap` | 如果值存在,就對該值執行提供的 mapping 函數調用,返回一個 Optional 類型的值,否則就返 回一個空的 Optional 對象 |
| `get` | 如果該值存在,將該值用 Optional 封裝返回,否則拋出一個 NoSuchElementException 異常 |
| `ifPresent` | 如果值存在,就執行使用該值的方法調用,否則什么也不做 |
| `isPresent` | 如果值存在就返回 true,否則返回 false |
| `of` | 將指定值用 Optional 封裝之后返回,如果該值為 null,則拋出一個 NullPointerException 異常 |
| `ofNullable` | 將指定值用 Optional 封裝之后返回,如果該值為 null,則返回一個空的 Optional 對象 |
| `orElse` | 如果有值則將其返回,否則返回一個默認值 |
| `orElseGet` | 如果有值則將其返回,否則返回一個由指定的 Supplier 接口生成的值 |
| `orElseThrow` | 如果有值則將其返回,否則拋出一個由指定的 Supplier 接口生成的異常 |
- 第零章 序
- 序言
- 系統架構
- 視頻公開課
- 開源版介紹
- 商業版介紹
- 功能對比
- 答疑流程
- 第一章 快速開始
- 升級必看
- 環境要求
- 環境準備
- 基礎環境安裝
- Docker安裝基礎服務
- Nacos安裝
- Sentinel安裝
- 插件安裝
- 建數據庫
- 工程導入
- 導入Cloud版本
- 導入Nacos配置
- 導入Boot版本
- 工程運行
- 運行Cloud版本
- 運行Boot版本
- 工程測試
- 測試Cloud版本
- 測試Boot版本
- 第二章 技術基礎
- Java
- Lambda
- Lambda 受檢異常處理
- Stream 簡介
- Stream API 一覽
- Stream API (上)
- Stream API (下)
- Optional 干掉空指針
- 函數式接口
- 新的日期 API
- Lombok
- SpringMVC
- Swagger
- Mybatis
- Mybatis-Plus
- 開發規范
- 第三章 開發初探
- 新建微服務工程
- 第一個API
- API鑒權
- API響應結果
- Redis緩存
- 第一個CRUD
- 建表
- 建Entity
- 建Service和Mapper
- 新增 API
- 修改 API
- 刪除 API
- 查詢 API
- 單條數據
- 多條數據
- 分頁
- 微服務遠程調用
- 聲明式服務調用 Feign
- 熔斷機制 Hystrix
- 第四章 開發進階
- 聚合文檔
- 鑒權配置
- 跨域處理
- Xss防注入
- 自定義啟動器
- Secure安全框架
- Token認證簡介
- Token認證配置
- PreAuth注解配置
- Token認證實戰
- Token認證加密
- 日志系統
- 原理解析
- 功能調用
- Seata分布式事務
- 簡介
- 編譯包啟動
- 配置nacos對接
- docker啟動
- 對接微服務
- 代碼生成配置
- 前言
- 數據庫建表
- 代碼生成
- 前端配置
- 優化效果
- 第五章 功能特性
- SaaS多租戶
- 概念
- 數據隔離配置
- 線程環境自定義租戶ID
- 多終端令牌認證
- 概念
- 系統升級
- 使用
- 第三方系統登錄
- 概念說明
- 對接說明
- 對接準備
- 配置說明
- 操作流程
- 后記
- UReport2報表
- 報表簡介
- 對接配置
- 報表后記
- 接口報文加密
- 簡介
- 運行邏輯
- 對接準備
- 功能配置
- 接口測試
- 改造查詢
- 改造提交
- 改造刪除
- 動態數據權限
- 數據權限簡介
- 數據權限開發
- 純注解配置
- Web全自動配置
- 注解半自動配置
- 數據權限注意點
- 動態接口權限
- 樂觀鎖配置
- 統一服務登陸配置
- Skywalking追蹤監控
- Minio分布式對象存儲
- Boot版本對接至Cloud
- 第六章 生產部署
- windows部署
- linux部署
- jar部署
- docker部署
- java環境安裝
- mysql安裝
- docker安裝
- docker-compose安裝
- harbor安裝
- 部署步驟
- 寶塔部署
- 準備工作
- 安裝工作
- 部署準備
- 部署后端
- 部署前端
- 部署域名
- 結束工作
- k8s平臺部署
- 第七章 版本控制
- Git遠程分支合并
- Git地址更換
- 第八章 學習資料
- 第九章 FAQ
- 第十章 聯系我們