Java 8 Optional 類
- 總述
- 類聲明
- 類常用的方法
- Optional 執行個體
- Optional在SpringBoot中的應用之一
- 另附一張Optional的API
總述
Optional 為java8的新特性
Optional 類是一個可以為null的容器對象。如果值存在則isPresent()方法會傳回true,調用get()方法會傳回該對象。
Optional 是個容器:它可以儲存類型T的值,或者僅僅儲存null。Optional提供很多有用的方法,這樣我們就不用顯式進行空值檢測。
Optional 類的引入很好的解決空指針異常。
類聲明
java.util.optional類的聲明
public filnal class Optional extends Object
類常用的方法
序号 | 方法 | 描述 |
---|---|---|
1 | static Optional empty() | 傳回空的 Optional 執行個體。 |
2 | boolean equals(Object obj) | 判斷其他對象是否等于 Optional。 |
3 | Optional filter(Predicate<? super predicate>) | 如果值存在,并且這個值比對給定的 predicate,傳回一個Optional用以描述這個值,否則傳回一個空的Optional。 |
4 | Optional flatMap(Function< ? Super T>,Optional mapper) | 如果值存在,傳回基于Optional包含的映射方法的值,否則傳回一個空的Optional |
5 | T get() | 如果在這個Optional中包含這個值,傳回值,否則抛出異常:NoSuchElementException |
6 | boolean isPresent() | 如果值存在則方法會傳回true,否則傳回 false。 |
7 | static Optional of(T value) | 傳回一個指定非null值的Optional。 |
8 | static Optional ofNullable(T value) | 如果為非空,傳回 Optional 描述的指定值,否則傳回空的 Optional。 |
9 | T orElse(T other) | 如果存在該值,傳回值, 否則傳回 other。 |
10 | T orElseGet(Supplier<? extends T> other) | 如果存在該值,傳回值, 否則觸發 other,并傳回 other 調用的結果。 |
11 | T orElseThrow(Supplier<? extends X> exceptionSupplier) | 如果存在該值,傳回包含的值,否則抛出由 Supplier 繼承的異常 |
Optional 執行個體
import java.util.Optional;
public class Java8Tester {
public static void main(String args[]){
Java8Tester java8Tester = new Java8Tester();
Integer value1 = null;
Integer value2 = new Integer(10);
// Optional.ofNullable - 允許傳遞為 null 參數
Optional<Integer> a = Optional.ofNullable(value1);
// Optional.of - 如果傳遞的參數是 null,抛出異常 NullPointerException
Optional<Integer> b = Optional.of(value2);
System.out.println(java8Tester.sum(a,b));
}
public Integer sum(Optional<Integer> a, Optional<Integer> b){
// Optional.isPresent - 判斷值是否存在
System.out.println("第一個參數值存在: " + a.isPresent());
System.out.println("第二個參數值存在: " + b.isPresent());
// Optional.orElse - 如果值存在,傳回它,否則傳回預設值
Integer value1 = a.orElse(new Integer(0));
//Optional.get - 擷取值,值需要存在
Integer value2 = b.get();
return value1 + value2;
}
}
輸出結果為:
$ javac Java8Tester.java
$ java Java8Tester
第一個參數值存在: false
第二個參數值存在: true
10
示例重點解析:正常情況為value1 + value2=null+10會報錯,使用Optional後可以計算值
Optional在SpringBoot中的應用之一
Spring Boot 2.0中,在将原來的泛型改為了Optional,旨在讓我們的代碼更簡潔。
Optional findById(ID var1)
實踐
Optional
很簡單的一個類,點開它的源代碼,其中所有的方法都是與null相關聯的。

這是一個簡化我們處理null的類。
它就是一個容器,其中有我們想要的對象,但是該對象有時候會是空,是以我們需要使用Optional封裝好的方法來擷取需要的對象。進而很好地避免了空指針異常。
錯誤示範
我看到網上很多人這麼寫:catRepository.findById(id).get();
下面是Spring Boot 1.5的寫法,那請問:如果上面的寫法是正确的,那為什麼還要大費周章設計一個Optional呢?
catRepository.findOne(id);
分析
通過get是能擷取到我們需要的對象。
但是看看get的源代碼,這樣寫,抛出了NoSuchElementException異常,這個異常我們沒法在全局中處理它。
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value; }
因為NoSuchElementException覆寫的範圍太廣了,隻要是Optional中有null就會抛出NoSuchElementException,很多情況下都會造成這種異常,那我們究竟要給使用者一個什麼樣的提示資訊好呢?最後還是給出500伺服器異常,那異常處理的意義何在呢?
是以我們需要用Optional來抛出一個有特定範圍的能被全局準确處理的異常。
Cat cat = catRepository.findOne(id);
if (null == cat) {
throw new EntityNotFoundException("該實體找不到");
}
return cat;
思想都是一樣,我們不過是用一種更簡潔的寫法實作上面的功能。
實作
沒錯,就像下面一樣,我們隻需要一行代碼!
public Cat findById(Long id) {
return catRepository.findById(id).orElseThrow(EntityNotFoundException::new); }
findById傳回一個Optional,然後調用該對象的orElseThrow方法。
orElseThrow方法,如果存在,傳回包含的值,否則抛出異常。
該方法的參數是一個lamda表達式。這裡就不深究lamda表達式的幾種類型了,如果感興趣可以自行研究下Function、Consumer、Predicate、Supplier這四個函數式接口的差別。
是以傳一個lamda表達式進去,然後IDEA會給出警告:
Can be replaced with method reference
該lamda表達式能被一個方法引用代替,Alt + Enter,我們最終的代碼就長這樣:
這裡的::是lamda表達式的一種簡寫,是Java8中的新特性,看着可能有點奇怪,原來,編譯器比程式員聰明多了。
異常處理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<String> entityNotFoundHandler() {
return new ResponseEntity<>("您要找的實體不存在", HttpStatus.NOT_FOUND); } }
寫個控制器增強,全局處理異常,這裡的RestControllerAdvice又是一個組合注解:
處理異常,同時以Json的格式傳回。