Java Optional 實踐

問題描述

在大熱的Spring Boot 2.0中,在將原來的泛型改成了Optional,旨在讓咱們的代碼更簡潔。java

clipboard.png

實踐

Optional

很簡單的一個類,點開它的源代碼,其中全部的方法都是與null相關聯的。程序員

clipboard.png

這是一個簡化咱們處理null的類。spring

它就是一個容器,其中有咱們想要的對象,可是該對象有時候會是空,因此咱們須要使用Optional封裝好的方法來獲取須要的對象。從而很好地避免了空指針異常。服務器

clipboard.png

錯誤示範

我看到網上不少人這麼寫:框架

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;
}

爲何不能再全局中處理呢?你們能夠思考一下:this

由於NoSuchElementException覆蓋的範圍太廣了,只要是Optional中有null就會拋出NoSuchElementException,不少狀況下都會形成這種異常,那咱們究竟要給用戶一個什麼樣的提示信息好呢?最後仍是給出500服務器異常,那異常處理的意義何在呢?spa

因此咱們須要用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方法。

clipboard.png

orElseThrow方法,若是存在,返回包含的值,不然拋出異常。

該方法的參數是一個lamda表達式。這裏就不深究lamda表達式的幾種類型了,若是感興趣能夠自行研究下FunctionConsumerPredicateSupplier這四個函數式接口的區別。

clipboard.png

因此傳一個lamda表達式進去,而後IDEA會給出警告:

clipboard.png

Can be replaced with method reference

lamda表達式能被一個方法引用代替,Alt + Enter,咱們最終的代碼就長這樣:

clipboard.png

這裏的::lamda表達式的一種簡寫,是Java8中的新特性,看着可能有點奇怪,原來,編譯器比程序員聰明多了。

異常處理

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(EntityNotFoundException.class)
    public ResponseEntity<String> entityNotFoundHandler() {
        return new ResponseEntity<>("您要找的實體不存在", HttpStatus.NOT_FOUND);
    }
}

寫個控制器加強,全局處理異常,這裏的RestControllerAdvice又是一個組合註解:

clipboard.png

處理異常,同時以Json的格式返回。

@Test
public void findById() throws Exception {
    this.mockMvc.perform(get("/cat/1"))
            .andDo(print());
}

寫個控制器的單元測試,查詢一個不存在的實體,運行,看控制檯的打印輸出:

clipboard.png

一勞永逸

一勞永逸,這是咱們最喜歡的東西了。

return catRepository.findById(id).orElseThrow(EntityNotFoundException::new);

之後再查詢,就這一行,不再用去判斷null了。

NotNull

正所謂條條大路通羅馬,對null的一勞永逸,咱們這樣實現,別人也能夠那樣實現。

若是你在Spring的項目中打過斷點調試的話,那我判定你必定見過下面這行代碼:

Assert.notNull();

如下是該方法的源碼,注意這裏的Assertorg.springframework.util包下的:

clipboard.png

剛方法用於判斷null,若是爲空,則拋出異常。

隨便點開一個方法,都會在第一行爲不應爲null的參數進行判斷。

clipboard.png

這裏,不由對整個框架肅然起敬。

總結

以前一直抱怨Java更新的太快:

clipboard.png

其實,Java的每次更新,都是爲了咱們更簡潔優雅的代碼而努力。去看看官方的描述,Java讓咱們將更多的精力放在think上,而不是code上。

相關文章
相關標籤/搜索