問題描述
在大熱的spring boot 2.0
中,在將原來的泛型改為了optional
,旨在讓我們的代碼更簡潔。
實踐
optional
很簡單的一個類,點開它的源代碼,其中所有的方法都是與null
相關聯(lián)的。
這是一個簡化我們處理null
的類。
它就是一個容器,其中有我們想要的對象,但是該對象有時候會是空,所以我們需要使用optional
封裝好的方法來獲取需要的對象。從而很好地避免了空指針異常。
錯誤示范
我看到網(wǎng)上很多人這么寫:
1
|
catrepository.findbyid(id).get(); |
下面是spring boot 1.5
的寫法,那請問:如果上面的寫法是正確的,那為什么還要大費周章設計一個optional
呢?
1
|
catrepository.findone(id); |
分析
通過get
是能獲取到我們需要的對象。
但是看看get
的源代碼,這樣寫,拋出了nosuchelementexception
異常,這個異常我們沒法在全局中處理它。
1
2
3
4
5
6
|
public t get() { if (value == null ) { throw new nosuchelementexception( "no value present" ); } return value; } |
為什么不能再全局中處理呢?大家可以思考一下:
因為nosuchelementexception
覆蓋的范圍太廣了,只要是optional
中有null
就會拋出nosuchelementexception
,很多情況下都會造成這種異常,那我們究竟要給用戶一個什么樣的提示信息好呢?最后還是給出500
服務器異常,那異常處理的意義何在呢?
所以我們需要用optional
來拋出一個有特定范圍的能被全局準確處理的異常。
1
2
3
4
5
|
cat cat = catrepository.findone(id); if ( null == cat) { throw new entitynotfoundexception( "該實體找不到" ); } return cat; |
思想都是一樣,我們不過是用一種更簡潔的寫法實現(xiàn)上面的功能。
實現(xiàn)
沒錯,就像下面一樣,我們只需要一行代碼!
1
2
3
|
public cat findbyid( long id) { return catrepository.findbyid(id).orelsethrow(entitynotfoundexception:: new ); } |
findbyid
返回一個optional
,然后調(diào)用該對象的orelsethrow
方法。
orelsethrow
方法,如果存在,返回包含的值,否則拋出異常。
該方法的參數(shù)是一個lamda
表達式。這里就不深究lamda
表達式的幾種類型了,如果感興趣可以自行研究下function
、consumer
、predicate
、supplier
這四個函數(shù)式接口的區(qū)別。
所以傳一個lamda
表達式進去,然后idea
會給出警告:
can be replaced with method reference
該lamda
表達式能被一個方法引用代替,alt + enter
,我們最終的代碼就長這樣:
這里的::
是lamda
表達式的一種簡寫,是java8
中的新特性,看著可能有點奇怪,原來,編譯器比程序員聰明多了。
異常處理
1
2
3
4
5
6
7
8
|
@restcontrolleradvice public class globalexceptionhandler { @exceptionhandler (entitynotfoundexception. class ) public responseentity<string> entitynotfoundhandler() { return new responseentity<>( "您要找的實體不存在" , httpstatus.not_found); } } |
寫個控制器增強,全局處理異常,這里的restcontrolleradvice
又是一個組合注解:
處理異常,同時以json
的格式返回。
1
2
3
4
5
|
@test public void findbyid() throws exception { this .mockmvc.perform(get( "/cat/1" )) .anddo(print()); } |
寫個控制器的單元測試,查詢一個不存在的實體,運行,看控制臺的打印輸出:
一勞永逸
一勞永逸,這是我們最喜歡的東西了。
1
|
return catrepository.findbyid(id).orelsethrow(entitynotfoundexception:: new ); |
以后再查詢,就這一行,再也不用去判斷null
了。
notnull
正所謂條條大路通羅馬,對null
的一勞永逸,我們這樣實現(xiàn),別人也可以那樣實現(xiàn)。
如果你在spring
的項目中打過斷點調(diào)試的話,那我斷定你一定見過下面這行代碼:
1
|
assert .notnull(); |
以下是該方法的源碼,注意這里的assert
是org.springframework.util
包下的:
剛方法用于判斷null
,如果為空,則拋出異常。
隨便點開一個方法,都會在第一行為不該為null
的參數(shù)進行判斷。
這里,不禁對整個框架肅然起敬,同樣一個方法,大牛寫了二十分鐘,而你寫了十分鐘,但是你卻去改了半個小時的bug
。
@nullable
可能在上面看到了我們不熟悉的注解@nullable
,表示從來沒見過,這個注解干什么用的呢?
萬能的stackoverflow
又給出了完美的回答:
這會讓你的代碼更清晰,如果你重寫這個方法,你也需要讓參數(shù)可為空。通常也用于代碼提示。
@nullable
和@notnull
這一對注解,沒什么實際意義,只是用于代碼更清晰,同時編譯器能給出我們提示。
總結(jié)
之前一直抱怨java
更新的太快,學校教的是java5
之前的東西,從java5
開始有的注解,但是從來沒講過這個東西,然而去看看官方的描述:
其實,java
的每次更新,都是為了我們更簡潔優(yōu)雅的代碼而努力。去看看官方的描述,java
讓我們將更多的精力放在think
上,而不是code
上。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://segmentfault.com/a/1190000016502649