如何正確定義自定義異常?繼承RuntimeException和Exception的關鍵選擇依據是什么?

自定義異常的核心在于根據異常是否需要強制處理來選擇繼承runtimeexception或exception。繼承runtimeexception適用于程序邏輯錯誤,如參數校驗失敗,無需強制處理,編譯器不檢查;繼承exception適用于外部因素導致的錯誤,如文件不存在,必須try-catch或throws聲明。創建自定義異常需定義類并添加屬性方法,如mycustomexception含errorcode,mycustomruntimeexception含detailmessage。拋出時dosomething需聲明throws,而dosomethingelse無需聲明。處理時分別捕獲并輸出信息。避免濫用自定義異常,優先使用標準異常類,僅在必要時擴展。線程中可用uncaughtexceptionhandler或future.get()處理異常。spring boot中可結合@controlleradvice、@exceptionhandler、errorattributes及responseentityexceptionhandler實現全局異常管理。

如何正確定義自定義異常?繼承RuntimeException和Exception的關鍵選擇依據是什么?

定義自定義異常,說白了就是為了更精準地處理程序中可能出現的各種“意外”。至于繼承 RuntimeException 還是 Exception,這可不是隨便選的,背后藏著不少門道。簡單來說,RuntimeException 是非受檢異常,編譯器不會強制你必須處理;而 Exception 是受檢異常,不 try-catch 或者 throws 聲明,編譯器就跟你過不去。

如何正確定義自定義異常?繼承RuntimeException和Exception的關鍵選擇依據是什么?

解決方案

如何正確定義自定義異常?繼承RuntimeException和Exception的關鍵選擇依據是什么?

自定義異常,核心在于創建一個新的類,繼承自 Exception 或者 RuntimeException,然后根據你的需求添加一些自定義的屬性和方法。

  1. 創建自定義異常類

    如何正確定義自定義異常?繼承RuntimeException和Exception的關鍵選擇依據是什么?

    // 繼承 Exception(受檢異常) class MyCustomException extends Exception {     private int errorCode;      public MyCustomException(String message, int errorCode) {         super(message);         this.errorCode = errorCode;     }      public int getErrorCode() {         return errorCode;     } }  // 繼承 RuntimeException(非受檢異常) class MyCustomRuntimeException extends RuntimeException {     private String detailMessage;      public MyCustomRuntimeException(String message, String detailMessage) {         super(message);         this.detailMessage = detailMessage;     }      public String getDetailMessage() {         return detailMessage;     } }
  2. 拋出自定義異常

    public void doSomething(int value) throws MyCustomException { // 必須聲明 throws     if (value < 0) {         throw new MyCustomException("Value cannot be negative", 1001);     }     // ... }  public void doSomethingElse(String input) { // 無需聲明 throws     if (input == null || input.isEmpty()) {         throw new MyCustomRuntimeException("Input cannot be null or empty", "Invalid input received");     }     // ... }
  3. 處理自定義異常

    try {     doSomething(-1); } catch (MyCustomException e) {     System.err.println("Caught MyCustomException: " + e.getMessage() + ", Error Code: " + e.getErrorCode()); }  try {     doSomethingElse(null); } catch (MyCustomRuntimeException e) {     System.err.println("Caught MyCustomRuntimeException: " + e.getMessage() + ", Detail: " + e.getDetailMessage()); }

什么時候該選擇繼承 RuntimeException?

考慮一下這樣的場景:一個方法被調用了無數次,每次調用都強制進行異常處理會顯得非常繁瑣,甚至影響代碼的可讀性。比如,空指針異常 NullPointerException,你總不能每次用到對象都 try-catch 一下吧?繼承 RuntimeException 的異常通常表示程序邏輯錯誤,這種錯誤應該在開發階段就避免,而不是在運行時依賴異常處理。

  • 場景舉例: 參數校驗失敗,比如傳入的參數明顯不符合業務規則,這種錯誤更應該在代碼層面避免。
  • 適用情況: 你認為這種異常的發生是不可避免的,或者處理起來成本太高,不如讓程序直接崩潰,然后修復 bug

什么時候該選擇繼承 Exception?

如果你的異常是由于外部因素導致的,比如網絡連接中斷、文件不存在等,這些情況是程序無法完全控制的,那么就應該繼承 Exception。 強制要求調用者處理這些異常,可以提高程序的健壯性。

  • 場景舉例: 讀取配置文件時,文件不存在,這種情況是程序無法保證的。
  • 適用情況: 你希望調用者能夠明確地知道這個方法可能會拋出異常,并且強制他們進行處理,避免程序在運行時出現未知的錯誤。

如何避免過度使用自定義異常?

自定義異常雖然強大,但也不能濫用。過多的異常定義會讓代碼變得復雜,難以維護。

  • 考慮使用現有的異常類: Java 已經提供了很多標準的異常類,比如 IllegalArgumentException、IOException 等,如果你的異常可以用這些類來表示,就盡量不要自定義。
  • 只在必要的時候自定義異常: 只有當你需要添加額外的屬性或者方法來描述異常信息時,才考慮自定義異常。
  • 保持異常的層次結構清晰: 如果你的應用有很多自定義異常,可以考慮使用繼承來組織它們,保持代碼的結構清晰。

如何在多線程環境中使用自定義異常?

在多線程環境中,異常的處理會更加復雜。你需要確保每個線程都能正確地處理異常,避免程序崩潰。

  • 使用 Thread.UncaughtExceptionHandler: 可以為每個線程設置一個 UncaughtExceptionHandler,用于處理線程中未捕獲的異常。
  • 使用 Future 獲取異常: 如果你的線程是通過 ExecutorService 提交的,可以使用 Future 的 get() 方法來獲取線程執行過程中拋出的異常。
  • 避免在線程之間傳遞異常: 盡量避免在不同的線程之間傳遞異常,這會導致代碼的復雜度增加。

如何在 spring boot 中使用自定義異常?

Spring Boot 提供了強大的異常處理機制,可以讓你輕松地處理自定義異常。

  • 使用 @ControllerAdvice 和 @ExceptionHandler: 可以創建一個全局的異常處理類,使用 @ControllerAdvice 和 @ExceptionHandler 注解來處理不同類型的異常。
  • 自定義 ErrorAttributes: 可以自定義 ErrorAttributes 來添加額外的異常信息到響應中。
  • 使用 ResponseEntityExceptionHandler: 可以繼承 ResponseEntityExceptionHandler 來定制 Spring mvc 的異常處理行為。

總之,選擇繼承 RuntimeException 還是 Exception,取決于你的應用場景和設計目標。理解它們的區別,合理地使用自定義異常,可以提高代碼的質量和可維護性。

? 版權聲明
THE END
喜歡就支持一下吧
點贊6 分享