函數出錯返回的數據類型

函數出錯返回的數據類型有4中情況:錯誤碼NULL值空對象異常對象

1. 錯誤碼

  • C語言中沒有異常這樣的語法機制,返回錯誤碼便是最常用的的出錯處理方式。
  • Java、Python等比較新的編程語言中,大部分情況下,我們都用異常來處理函數出錯的情況,極少會用到錯誤碼。

2. 返回NULL值

  • 多數編程語言中,NULL用來表示「不存在」的語義。
  • 對於查找函數(get、find、select、search、query 等單詞開頭的函數),數據不存在是一種正常行為,並非是一種異常情況,所以返回表示不存在語義的NULL值比返回異常更合理。

2.1 弊端

很多人認為返回NULL值是一種不好的設計思路的兩個主要理由:

  • 若函數可能返回NULL值,當使用時忘記做NULL值判斷,可能會拋出空指針異常(Null Pointer Exception,NPE)。
  • 若定義了很多返回值可能為NULL值的函數,代碼中會充斥大量的NULL值判斷邏輯,寫起來比較繁瑣,同時和正常業務邏輯耦合在一起,影響代碼可讀性。

3. 返回空對象

返回NULL值有各種弊端,對此有一個比較經典的應對策略,就是應用空對象設計模式(Null Object Design Pattern)。

當函數返回的數據是字符串類型或者集合類型的時候,我們可以用空字符串或空集合替代 NULL 值,來表示不存在的情況。這樣,我們在使用函數的時候,就可以不用做 NULL 值判斷。

public List<User> getUsers(String phonePrefix) {      // 未找到數據      return Collections.emptyList();  }    public String getUserName(Long id) {      // 未找到數據      return "";  }

4. 拋出異常對象

最常用的函數出錯處理方式是拋出異常。異常有兩種類型:受檢異常和非受檢異常。

至於孰好孰壞,只需要根據團隊的開發習慣,在同一個項目中,制定統一的異常處理規範即可。

對於函數拋出的異常,我們有三種處理方法:直接吞掉、直接往上拋出、包裹成新的異常拋出。

返回 NULL 值還是異常對象,要看獲取不到數據是正常行為,還是異常行為。獲取信息失敗會影響後續邏輯的處理,並不是我們期望的,此時便是一種異常行為,最好拋出異常。

我們需要明確地告知調用者的異常時不可直接吞掉。

4.1 是否要在函數中做 NULL 值或空字符串的判斷

  • 如果函數是 private 類私有的,只在類內部被調用,完全在你自己的掌控之下,自己保證在調用這個 private 函數的時候,不要傳遞 NULL 值或空字符串就可以了。所以,我們可以不在 private 函數中做 NULL 值或空字符串的判斷。
  • 如果函數是 public 的,你無法掌控會被誰調用以及如何調用(有可能某個同事一時疏忽,傳遞進了 NULL 值,這種情況也是存在的),為了儘可能提高代碼的健壯性,我們最好是在 public 函數中做 NULL 值或空字符串的判斷。

4.2 需要包裹成新異常拋出的條件

  • 當依賴抽象而非實現編程,即調用者調用函數時只知道功能不需要知道底層實現時,直接拋出底層異常實際上暴露了實現細節。
  • 從代碼封裝的角度,並不希望將比較底層的異常暴露給更上層的代碼,而且調用者拿到該異常時並不能理解這個異常到底代表了什麼,也不知道該如何處理。
  • 異常跟調用者調用的函數,在業務概念上沒有相關性。

參考資料

設計模式之美