Optional

Optional類入門

java.util.Optional<T>是java8中引入的一個新類,這是一個封裝了Optional值的類。

變量存在時,Optional類只是對類簡單封裝。變量不存在時,缺失的值會被建模成一個“空”的Optional對象,由方法Optional.empty()返回。

Optional.empty()方法是一個靜態工廠方法,它返回Optional類的特定單一實例。

Optional與傳統代碼的區別
//傳統代碼
public GroupParams  verifyGroupID(Long groupID){
    if (CommonUtils.isNull(groupID)){
        return null;
    }
    //根據groupID查詢集團會員參數信息
    GroupParams groupParams = groupParamsMapper.queryByGroupID(groupID);
    if(CommonUtils.isNull(groupParams)){
        return null;
    }
    return groupParams;
}
 
//引入Optional(加入了自定義異常機制,可以拋出異常之後,由異常捕獲機制直接講錯誤碼告知端,無需在方法層面多次判斷)
public GroupParams verifyGroupID(Long groupID) {
 
    try{
       return of(groupID)
                .map(gID -> groupParamsMapper.queryByGroupID(gID))
                .orElseThrow(() -> new BusinessException(ErrorCode.GROUP_ID_NOT_EXISTS));
    }catch (NullPointerException e){
        throw new BusinessException(ErrorCode.EMPTY_GROUP_ID);
    }
}

應用Optional的幾種模式

創建Optional對象

聲明一個空的Optional

通過靜態工廠方法Optional.empty,創建一個空的Optional對象:

聲明一個空的Optional
Optional<CardInfo> optCard = Optional.empty();

依據一個非空值創建Optional

使用靜態工廠方法Optional.of,依據一個非空值創建一個Optional對象:

如果cardInfo是一個null,這段代碼會立即跑出一個NullPointerException,而不是等到試圖訪問cardInfo的屬性值時才返回一個錯誤。

依據一個非空值創建Optional
Optional<CardInfo> optCard = Optional.of(cardInfo);

可接受null的Optional

使用靜態方法Optional.ofNullable,可以創建一個允許null值的Optional對象:

可接受null的Optional
Optional<CardInfo> optCard = Optional.ofNullable(cardInfo);

使用map從Optional對象中提取值和轉換值

Optional提供了一個map方法,可以從Optional中獲取對象中的某些屬性值,map方法接收一個Function對象

使用map從Optional對象中提取值
//聲明一個Optional<CardInfo>對象,從中獲取cardNO的值,無論cardinfo是否爲null,下面代碼都不會拋出異常
Optional<CardInfo> optCard = Optional.ofNullable(cardInfo);
Optional<String> optCardNO = optCard.map(CardInfo::getCardNO);

 

使用flatMap鏈接Optional對象

再使用流的時候,flatMap方法接受一個函數作爲參數,這個函數的返回值是另一個流。這個方法會應用到流中的每一個元素,最終形成一個新的流的流。

但是flatMap會用流的內容替換每個新生成的流。換句話說,由方法生成的各個流會被合併或者或者扁平化爲一個單一的流。

當需要鏈接多個Optional對象時,使用flatMap可以將多個Optional對象轉換爲單一的Optional對象。

使用flatMap鏈接Optional對象
//組合多個Optional對象,並返回一個包裝cardTypeID的Optional對象
private Optional<Long> getCardTypeId(Optional<Long> groupIDOptional, Optional<Long> shopIDOptional){
 
    return groupIDOptional.flatMap(gID -> shopIDOptional.filter(sID -> sID > 0).map(sID -> cardTypeShopMapper.selectByGroupIDAndShopID(gID,sID))).map(s -> s.getCardTypeID());
}

默認行爲及解引用Optional對象

Optional類提供了多種方法獲取Optional實例中的變量值。

  • get()
  • orEles(T other)
  • orElseGet(Supplier<? extends T> other)  是orElse的延遲調用版
  • orElseThrow(Supplier<? extends X> exceptionSupplier)
  • ifPresent(Consumer<? super T>)

使用filter剔除特定的值

filter方法接受一個謂詞作爲參數。如果Optional對象的值存在,並且它符合謂詞的條件,filter方法就返回其值;否則它就返回一個空的Optional對象。

使用filter剔除特定的值
//通過filter過濾狀態值大於0  並且不與當前傳遞的狀態值相等的狀態
public Optional<Integer> canUpdateCardStatus(Integer optionType,Integer cardStatus){
        try{
           return  of(optionType)
                   .flatMap(o -> of(cardStatus).map(s -> CardLogTypeEnum.getCardLogTypeEnum(o).getStatusAfterChange()))
                   .filter( i -> i > 0 && i != cardStatus);
       }catch (NullPointerException e){
              throw new BusinessException(ErrorCode.EMPTY_UPDATE_CARD_STATUS_PARAM);
       }
    }

Optional類的方法

方法
描述
empty

返回一個空的Optional實例

filter 如果值存在並且滿足提供的謂詞,就返回包含該值的Optional對象;否則返回一個空的Optional對象
flatMap 如果值存在,就對該值執行提供的mapping函數調用,返回一個Optional類型的值,否則就返回一個空的Optional對象
get 如果該值存在,將該值用Option封裝返回,否則跑出一個NoSuchelementException異常
ifPresent 如果值存在,就執行使用該值的方法調用,否則什麼都不做
isPresent 如果值存在就返回true,否則則返回false
map 如果值存在,就對該值執行提供的mapping函數調用
of 將指定值用Optional封裝之後返回,如果該值爲null,則拋出一個NullPointerException異常
ofNullable

將指定值用Optional封裝之後返回,如果該值爲null,則返回一個空的Optional對象

orElse

如果有值則將其返回,否則返回一個由指定的Supplier接口生成的值
orElseThrow 如果有值則將其返回,否則拋出一個由指定的Supplier接口生成的異常

 

注意:

  1. Optional的設計初衷僅僅是要支持能返回Optional對象的語法。由於Optional類設計時就沒特別考慮將其作爲類的字段使用,所以它也並未實現Serializable接口。由於這個原因,如果你的應用使用了某些要求序列化的庫或者框架,在域模型中使用Optional,有可能引發程序故障。
  2. Optional也提供了基本數據類型的Optional對象,比如OptionalInt,OptionalLong,OptionalDouble,但是由於它們不支持map,flatMap,filter方法,而這些方法是Optional對象中最有用的方法。基礎類型的Optional對象不能組合使用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章