簡體   English   中英

Java:何時跳過對象的空檢查?

[英]Java : When to skip null checks on an object?

我在Java代碼中使用了很多防御性空檢查。 盡管他們很好地服務於他們的目的(大部分時間),但是他們的代碼與“丑陋”的代碼進行了巨大的交易。

將這些空檢查始終放入是否真的有意義? 例如:

if(object == null){
  log.error("...")
  throw new SomeRuntimeException("");
} else{
  object.someMethod();
}

實際上,上面的代碼相當於語句object.someMethod();

如果object的值為null,則在兩種情況下都會拋出異常(后面的NullpointerException)。

掩碼NullpointerExcetion(NPE)並拋出一些自定義RunTimeException(如上面的代碼片段)真的有意義嗎? 我觀察到一些開發人員將NPE視為邪惡,經常試圖找出掩蓋它的防御方法並用一些自定義異常掩蓋它。 這種掩蔽真的需要嗎?

  1. 如果我們無法從該null狀態恢復,那么允許我們的代碼通過NPE失敗是否有意義? (在上面的例子中,它似乎是一個不可恢復的場景。)
  2. 如果沒有,為什么?

在您發布的情況下,支票沒有任何好處。 你將一個RuntimeException替換為另一個沒有額外信息或價值的RuntimeException(對於不熟悉你的代碼的人來說可能一點,因為每個人都知道NPE是什么,並不是每個人都知道你的SomeRuntimeException是什么)。

我考慮明確檢查的主要兩次是:

  1. 當我想拋出一個已檢查的異常而不是未選中時。
  2. 當我想在實際使用引用之前檢查null。

第二種情況尤其重要,因為我只是為了以后存儲引用:例如,在構造函數中。 在這種情況下,當有人使用引用並觸發NPE時,可能很難找到那個null的位置。 通過在將其保存到字段之前檢查它,您更有可能找到根本原因。 事實上,這是一個常見的模式,JDK甚至為它提供了requireNonNull幫助器。

如果你看一下很多成熟的,高信譽的項目,我想你會發現“只是使用它,如果它發生就讓NPE發生”模式很常見。 舉一個例子,JDK的Collections.sort的代碼就是list.sort(null) ,其中list是方法參數。 如果它為null,那么該行將拋出一個NPE。

對於內部代碼,一堆空檢查是沒用的。 如果你將null傳遞給一個不期望它的方法,那么讓NPE失敗是可以接受的,而不是試圖防止錯誤。 如果您的代碼是從您無法控制的其他代碼調用的,則可以在方法的開頭聲明(Objects.requireNonNull),或者提供一個聲明傳入null的結果的Javadoc。 后一種方法在JDK代碼庫中普遍使用。

NPE被認為是不好的,因為它們對剛剛發生的問題沒有“語義”。 關於Java應用程序中的任何代碼段都可能會拋出NPE。 因此,當它發生時,你沒有立即知道導致NPE的原因:缺少用戶條目? 編程錯誤? 濫用外部依賴?

由於各種可能的原因,在上層捕捉NPE來處理這個問題是非常糟糕的做法

所以,當你有可能時,比如你給出的例子,在你編寫代碼時,你就知道當object == null時它意味着什么。 因此,如果您選擇拋出具有語義含義的異常,則可以在上層特別捕獲它,並在功能上處理此特殊情況。

關於樣板if(... == null)else ...,如果使用Java 8和Optionals ,則可以避免使用它

我編寫了一個個人類ArgumentChecker.java,包含許多常用的簡單靜態方法進行異常檢查,如checkPositive(double value),checkEquals(int v1,int v2),checkNonDecreasingOrder(int ... args),checkNonNull(Object obj) ,......等兩個例子如下。

public static void checkAllEqualsTo(int theValue, int... values){
    for (int i = 0; i < values.length; i++) { // StringUtils is also a personal simple class containing some wrapped methods
        if (values[i] != theValue)
            throw new IllegalStateException(NOT_ALL_EQUAL_EXCEPTION + "; values = " + StringUtils.toString(values, values.length) + ", theValue = " + theValue);

    }
}

public static void checkAllEquals(int... values){
    if (values.length == 0){
        return;
    }
    checkAllEqualsTo(values[0], values);
}

這些方法是可重用的,對這些異常檢查方法的方法調用也簡潔易讀。

對於這個問題,代碼變為:

ArgumentCheck.checkNonNull(object);
object.someMethod();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM