2016-08-23 34 views
-1

當一個子方法拋出一個異常時,封裝在專用的「包」異常中會被認爲是不錯的實踐嗎?通過組件拋出異常,良好實踐?

public String doStuff() throws UtilsException { 
     try { 
      throw new NullPointerException("test"); 
     } catch (NullPointerException e) { 
      throw new UtilsException("something occured", e); 
     } 
    } 

    //use this exception for all classes of this package/component 
    public class UtilsException extends Exception { 
     private static final long serialVersionUID = 1L; 

     public UtilsException() { 
      super(); 
     } 

     public UtilsException(String message, Throwable cause) { 
      super(message, cause); 
     } 

     public UtilsException(String message) { 
      super(message); 
     } 

     public UtilsException(Throwable cause) { 
      super(cause); 
     } 

    } 

可能Optional.empty()是避免拋/複雜的應用程序的捕捉的方法嗎?

public Optional<String> doStuff() throws UtilsException { 
     try { 
      return Optional.of("ok"); 
     } catch (NullPointerException e) { 
      LOG.error("Something append... {}", e.getMessage()); 
      return Optional.empty(); 
     } 
    } 
+1

在某些設置中將低級異常包裝爲高級異常可能是一種很好的做法,但是如果您正在討論'NullPointerException',則不是。你甚至不應該捕獲一個'NullPointerException'。它在你的所有應用程序中具有相同的含義。一個'Optional'封裝了一個可能缺少的值,而不是一個發生'NullPointerException'的報告。首先避免'NullPointerException'。你可以通過使用'Optional'來做到這一點。 – Holger

+0

NullPointerException只是爲了解釋我的設置。遵循異常的來源,包裝看起來很有趣。 –

+1

然後你選擇了一個非常糟糕的例子。考慮一下,一個'ClassNotFoundException'封裝了加載類字節時發生的IOException。特殊情況是API層不允許檢查異常,例如考慮數據庫的「集合」視圖。在那裏,底層存儲系統的故障必須被打包,例如,在'IllegalStateException's或'NoSuchElementException's中。我認爲,這些都是更好的例子。 – Holger

回答

1

首先,你應該永遠一個NullPointerException(或運行時異常一般)的回報成才別的喜歡你正在做的。 好吧,也許有一些情況下,你需要這樣做(像一個越野車第三方api)。

當你的程序有一個錯誤,你應該讓它們冒泡並在你的程序的一些高階組件中處理它們時,會發生類似於那些(NullPointer,ClassCast,IllegalArgument等)的異常。

話雖這麼說,(有來自臭名昭著的短語),這取決於...

例外是錯誤的通知「負責」,因此他們需要信息的調用者將使用它們來什麼決定做。考慮以下幾點:

public void readFile(String path) throws IOException { 
    // read file content 
    return content; 
} 


try { 
    return readFile("foo.txt"); 
} catch(FileNotFound e) { 
    // For this specific scenario not finding the file is not a problem  
    return ""; 
} catch(IOException e) { 
    // This we are not expecting to happen, if the file exists we should be 
    // able to read it, otherwise we should inform the user. 
    log.error(e); 
    display("We had a problem reading the file, Check the file permissions and try again"); 
} 

正如你可以在上面的例子中看到的,你不會想換IOException異常的另一個異常在這種情況下 因爲你會刪除客戶端來決定做什麼時能力發生錯誤。

另外,還要注意IOException異常是「包裝」,因爲異常的對象也可以使用繼承 來概括你的方法將引發什麼樣的錯誤,然後拋出更具體的錯誤,以便調用者可以 決定形式是什麼去做。

何時換行。

有些情況下,包裝異常是一個很好的做法,是要走的路。 例如,如果您創建的主要功能是獲取天氣信息的庫。

對於第一個版本,您保持簡單並使用第三方api來獲取當天的值。 你的API的主要方法是這樣的。

public Weather getWeather(Date day) throws HTTPException { 
    return weather.get(day); 
} 

您的API是做得相當不錯,但你是否注意到你正在做太多的請求天氣API和 你將不得不很快開始爲它付出代價。然後您決定將結果緩存在數據庫表 中,以便減少請求數量。

public Weather getWeather(Date day) throws HTTPException, SQLException { 
    Weather w = getFromCache(day); 
    if (w != null) { 
     return w; 
    } else { 
     return getAndCache(day); 
    } 
} 

現在你有一個問題,在拋出的語句,因爲你肯定會打破你的 API的用戶代碼,你可以不加這個新的異常。

如果你仔細想想,如果你的緩存中存在從api或 獲取數據時出現問題,那麼你的api用戶不會感興趣,他們只是想知道錯誤。這是一個很好的例子,將 中的例外列入更通用的例外,如WeatherFetchException

正如你所看到的,它實際上取決於...

我的經驗法則是,保持你的例外有意義,如果你想包裝他們,只是做的時候 這是有道理的以及何時不刪除調用者處理錯誤的能力。

僅僅爲了它而包裝異常絕對不是一個好習慣。