Java8中Optional的正確使用姿勢

 

單純的使用Optional並不能很好的解決業務中的NPE問題 - 簡書
https://www.jianshu.com/p/f21afe47a3e7

 

 

單純的使用Optional並不能很好的解決業務中的NPE問題

 

工作中經常會遇到NPE(NullPointException)問題怎麼處理,得到最多的回答就是Optional來處理,但是單純的使用Optional並不能很好的解決業務中的NP問題。所以整理出日常工作中處理NPE問題的思路,供參考。

先看一下思路:

解決NPE的思路

 

 

01 錯誤的姿勢

01.01 避免入參使用 Optional

原因: 

1. 干擾閱讀者, 讓方法的意圖模糊

2. 別人在調用該方法時, 還需要專門new一個Optional後才能傳進來, 顯得調用繁瑣

日常工作中有是看到如下代碼。

public void execute(Optional<String> nameOptional) {
   ...
}

如果方法的某個參數可能爲null,那麼可以使用方法重載,而不是傳入一個null。因爲代碼的實現上揭示業務意圖要要好於只表示業務意圖,因爲在業務上null沒有業務意義,如果出現null,而又需要處理相關邏輯,那麼可以使用方法重載。

另外,方法調用者將很清晰起作用的參數,也不需要爲了調用某個方法而構造Optional。

public void execute() {
     execute(null);
}

public void execute(String name) {
    ...
}

上面的代碼避免了對外方法的意圖模糊,同時也避免了部分的重複代碼。

 

01.02 避免多行 if() 語句

原因: 

1. 如果在使用Optional, 還是出現多行的 if(xxxOptional.isPresent()) ...之類代碼, 那跟不用Optional的 if(xxx == null) 沒區別, 節約不了什麼成本

“使用了Optional,也沒有感覺邏輯變變簡單啊,每次都得get()方法”,這是工作中聽到的剛剛接觸Optional的開發人員的表述。

問題在哪裏呢?如果我們有一把把核桃夾子,但是每次用這把核桃夾子做的事情都是砸核桃,那麼就發現和用錘子砸也沒有什麼區別,結果都是碎了一地。

我們都說代碼時重構出來的,而不是設計出來的。所以實現的時候如果對Optional不熟悉可以使用if來判斷,重構的時候可以試着尋找一些能夠有更好的解決辦法。因爲switch語句本來就是壞味道,尋找的方向可以先看看Optional除了提供了get方法,還提供了哪些方法,它們都是做什麼用途的。

 

 

02 正確使用姿勢

02.01 返回值中用Optional顯式處理

如果實際實現中需要我們將null值返回,我們可以return一個Optioanl對象回去,這樣該方法的調用者就必須就知道返回中有可能爲null,並對其進行特定的處理。

public Optional<Data> execute() {
    ...
    return Optional.empty();
}

 

02.02 適當的時候使用Exception

並不是找不到結果我們就只能選擇返回Optional.empty(),除非邏輯需要繼續執行而不期望中斷,否則我們可以直接選擇拋出異常。

例如,根據username、password尋找用戶的方法,如果找不到用戶,可以直接拋出InvalidUsernameOrInvalidPasswordException。

public User login(String name, String password) {
    ...
    
    throw new InvalidUsernameOrInvalidPasswordException();
}

那麼,外層要麼進行異常處理,要麼Project進行全局異常捕獲,統一進行處理。

 

02.03 使用Optional Lambda

在01.02中提到了因爲對Optional提供的方法不熟悉,而感覺和null值判斷沒有多大區別。那麼推薦根據業務場景來選擇Optioanl Lambda的寫法。

String name = computer.flatMap(Computer::getSoundcard)
    .flatMap(Soundcard::getUSB)
    .map(USB::getVersion)
    .orElse("UNKNOWN");

上面寫法要比下面的寫法清晰很多。當然這需要保持好奇心,多學習一點工具類提供的方法,同時別總是製作簡單的搬磚工作。

String version = "UNKNOWN";
if (computer != null) {
    Soundcard soundcard = computer.getSoundcard();
    if (soundcard != null) {
        USB usb = soundcard.getUSB();
        if (usb != null) {
             version = usb.getVersion();
        }
    }
}

 

參考


02.03最終的代碼來源

 

發佈了101 篇原創文章 · 獲贊 126 · 訪問量 107萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章