<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 20 個 Java 異常處理最佳實踐 > 原文: [https://howtodoinjava.com/best-practices/java-exception-handling-best-practices/](https://howtodoinjava.com/best-practices/java-exception-handling-best-practices/) 這篇博文是此博客中[**最佳實踐**](//howtodoinjava.com/category/best-practices/ "java best practices")系列的又一篇文章。 在這篇文章中,我將介紹一些眾所周知的和鮮為人知的實踐,您在處理下一個 Java 編程任務中的異常時必須考慮這些實踐。 單擊此鏈接以閱讀有關 Java 中[**異常處理**](//howtodoinjava.com/category/java/exception-handling/ "exception handling")的更多信息。 ```java Table of Contents Type of exceptions User defined custom exceptions Best practices you must consider and follow Never swallow the exception in catch block Declare the specific checked exceptions that your method can throw Do not catch the Exception class rather catch specific sub classes Never catch Throwable class Always correctly wrap the exceptions in custom exceptions so that stack trace is not lost Either log the exception or throw it but never do the both Never throw any exception from finally block Always catch only those exceptions that you can actually handle Don't use printStackTrace() statement or similar methods Use finally blocks instead of catch blocks if you are not going to handle exception Remember "Throw early catch late" principle Always clean up after handling the exception Throw only relevant exception from a method Never use exceptions for flow control in your program Validate user input to catch adverse conditions very early in request processing Always include all information about an exception in single log message Pass all relevant information to exceptions to make them informative as much as possible Always terminate the thread which it is interrupted Use template methods for repeated try-catch Document all exceptions in your application in javadoc ``` 在深入探討異常處理最佳實踐的深入概念之前,讓我們從最重要的概念之一入手,這是要理解 Java 中存在三種可拋出類的常規類型:受檢的異常,非受檢的異常和錯誤。 ## 1\. Java 中的異常類型 ![Exception Hierarchy in java](https://img.kancloud.cn/7a/52/7a5265912c0646d95a47e76dc854821c_588x296.png "Exception Hierarchy in java") Java 中的異常層次結構 #### 受檢異常 這些是必須在方法的`throws`子句中聲明的異常。 它們擴展了`Exception`,旨在成為“面對您”的異常類型。 Java 希望您處理它們,因為它們某種程度上取決于程序之外的外部因素。 受檢的異常指示正常系統運行期間可能發生的預期問題。 通常,當您嘗試通過網絡或文件系統使用外部系統時,會發生這些異常。 通常,對檢查到的異常的正確響應應該是稍后重試,或者提示用戶修改其輸入。 #### 非受檢異常 這些是不需要在`throws`子句中聲明的異常。 JVM 不會強迫您處理它們,因為它們大多數是由于程序錯誤在運行時生成的。 它們擴展了`RuntimeException`。 最常見的示例是`NullPointerException`(很嚇人。不是嗎?)。 非受檢的異常可能不應該重試,正確的操作通常應該是什么也不做,然后讓它從方法中出來并通過執行棧。 在高級別執行時,應記錄此類異常。 #### 錯誤 是嚴重的運行時環境問題,幾乎可以肯定無法解決。 例如`OutOfMemoryError`,`LinkageError`和`StackOverflowError`。 它們通常會使您的程序或程序的一部分崩潰。 只有良好的日志記錄做法才能幫助您確定錯誤的確切原因。 ## 2.用戶定義的自定義異常 每當用戶出于某種原因而感覺到要使用其自己的應用特定異常時,他都可以創建一個擴展了適當超類(主要是`Exception`)的新類,并在適當的地方開始使用它。 這些用戶定義的異常可以兩種方式使用: 1. 當應用出現問題時,直接拋出自定義異常 ```java throw new DaoObjectNotFoundException("Couldn't find dao with id " + id); ``` 2. 或將原始異常包裝在自定義異常中,然后將其拋出 ```java catch (NoSuchMethodException e) { throw new DaoObjectNotFoundException("Couldn't find dao with id " + id, e); } ``` 包裝異常可以通過添加您自己的消息/上下文信息來向用戶提供額外的信息,同時仍保留原始異常的棧跟蹤和消息。 它還允許您隱藏代碼的實現細節,這是包裝異常的最重要原因。 現在讓我們開始探索在異常處理方面明智的最佳實踐。 ## 3.您必須考慮并遵循的 Java 異常處理最佳實踐 #### 3.1 永遠不要在`catch`塊中吞下異常 ```java catch (NoSuchMethodException e) { return null; } ``` 這樣做不僅返回“`null`”,而不是處理或重新引發異常,它完全吞沒了異常,永遠失去了錯誤原因。 而當您不知道失敗的原因時,將來如何預防呢? 永遠不要這樣做! #### 3.2 聲明您的方法可以拋出的特定受檢異常 ```java public void foo() throws Exception { //Incorrect way } ``` 始終避免像上面的代碼示例中那樣進行操作。 它根本無法達到受檢異常的全部目的。 聲明您的方法可以拋出的特定受檢異常。 如果此類受檢異常太多,則可能應將它們包裝在您自己的異常中,并在異常消息中添加信息。 如果可能,您還可以考慮代碼重構。 ```java public void foo() throws SpecificException1, SpecificException2 { //Correct way } ``` #### 3.3 不捕獲`Exception`類,而是捕獲特定的子類 ```java try { someMethod(); } catch (Exception e) { LOGGER.error("method has failed", e); } ``` 捕獲`Exception`的問題是,如果您稍后調用的方法在其方法簽名中添加了一個新的受檢的異常,則開發人員的意圖是您應該處理特定的新異常。 如果您的代碼只是捕獲到`Exception`(或`Throwable`),那么您將永遠不會知道更改以及您的代碼現在是錯誤的并且可能在運行時的任何時間中斷的事實。 #### 3.4 永不捕獲`Throwable` 好吧,這是更嚴重的麻煩了。 因為 Java 錯誤也是`Throwable`的子類。 錯誤是不可逆的條件,JVM 本身無法處理。 對于某些 JVM 實現,JVM 甚至可能實際上不會在`Error`上調用您的`catch`子句。 #### 3.5 始終正確地將異常包裝在自定義異常中,以便不會丟失棧跟蹤 ```java catch (NoSuchMethodException e) { throw new MyServiceException("Some information: " + e.getMessage()); //Incorrect way } ``` 這破壞了原始異常的棧跟蹤,并且總是錯誤的。 正確的方法是: ```java catch (NoSuchMethodException e) { throw new MyServiceException("Some information: " , e); //Correct way } ``` #### 3.6 記錄異常還是拋出異常,但不要兩者都做 ```java catch (NoSuchMethodException e) { LOGGER.error("Some information", e); throw e; } ``` 與上面的示例代碼一樣,由于代碼中的單個問題,日志記錄和拋出將導致日志文件中出現多條日志消息,并使試圖挖掘日志的工程師費盡心思。 #### 3.7 永遠不要從`finally`塊中拋出任何異常 ```java try { someMethod(); //Throws exceptionOne } finally { cleanUp(); //If finally also threw any exception the exceptionOne will be lost forever } ``` 只要`cleanUp()`永遠不會拋出任何異常,就可以了。 在上面的示例中,如果`someMethod()`引發異常,并且在`finally`塊中,`cleanUp()`引發異常,則第二個異常將從方法中消失,原始的第一個異常(正確原因)將永遠消失。 如果您在`finally`塊中調用的代碼可能會引發異常,請確保處理該異常或將其記錄下來。 永遠不要讓它脫離最后的障礙。 #### 3.8 始終僅捕獲您可以實際處理的異常 ```java catch (NoSuchMethodException e) { throw e; //Avoid this as it doesn't help anything } ``` 好吧,這是最重要的概念。 不要僅僅為了捕獲異常就捕獲任何異常。 僅在您要處理任何異常或要在該異常中提供其他上下文信息時才捕獲任何異常。 如果您無法在捕獲區中處理它,那么最好的建議就是不要僅將其重新拋出就捕獲它。 #### 3.9 不要使用`printStackTrace()`語句或類似方法 完成代碼后,切勿離開`printStackTrace()`。 很有可能是您的同事之一,最終將獲得這些棧跟蹤中的一個,并且對如何處理它的知識完全為零,因為它不會附加任何上下文信息。 #### 3.10 如果您不打算處理異常,請使用`finally`塊而不是`catch`塊 ```java try { someMethod(); //Method 2 } finally { cleanUp(); //do cleanup here } ``` 這也是一個好習慣。 如果在您的方法內部訪問某個方法 2,并且方法 2 拋出一些您不想在方法 1 中處理的異常,但是仍然希望進行一些清除以防萬一發生異常,那么請在`finally`塊中進行此清除。 不要使用擋塊。 #### 3.11 記住“早拋出晚捕獲”的原則 這可能是有關異常處理的最著名的原理。 它基本上說您應該盡快拋出異常,并盡可能晚地捕獲它。 您應該等待,直到掌握了正確處理所有信息為止。 該原則隱含地表明,您將更有可能將其扔到低級方法中,在這種方法中,您將檢查單個值是否為`null`或不合適。 并且您將使異常爬升到棧跟蹤相當多個級別,直到達到足夠的抽象級別以能夠解決問題為止。 #### 3.12 處理異常后請務必清理 如果您正在使用數據庫連接或網絡連接之類的資源,請確保清理它們。 如果要調用的 API 僅使用非受檢的異常,則仍應在使用后使用`try–finally`塊清理資源。 在`try`塊內部訪問資源,最后在內部關閉資源。 即使在訪問資源時發生任何異常,資源也將正常關閉。 #### 3.13 僅拋出方法中的相關異常 相關性對于保持應用清潔很重要。 一種嘗試讀取文件的方法; 如果拋出`NullPointerException`,則不會向用戶提供任何相關信息。 相反,如果將此類異常包裝在自定義異常中會更好,例如`NoSuchFileFoundException`,那么它將對該方法的用戶更加有用。 #### 3.14 切勿在程序中使用異常進行流控制 我們已經閱讀了很多次,但是有時我們會在項目中不斷看到代碼,在這些代碼中,開發人員試圖將異常用于應用邏輯。 絕對不要那樣做。 它使代碼難以閱讀,理解和難看。 #### 3.15 在請求處理的早期就驗證用戶輸入以捕獲不利條件 始終在很早的階段就驗證用戶輸入,甚至在輸入到實際控制器之前。 這將幫助您最大程度地減少核心應用邏輯中的異常處理代碼。 如果用戶輸入中存在一些錯誤,它還可以幫助您使應用保持一致。 例如:如果在用戶注冊應用中,您將遵循以下邏輯: 1)驗證用戶 2)插入用戶 3)驗證地址 4)插入地址 5)如果有問題,請回滾所有內容 這是非常不正確的方法。 在各種情況下,它會使數據庫處于不一致狀態。 而是首先驗證所有內容,然后在 dao 層中獲取用戶數據并進行數據庫更新。 正確的方法是: 1)驗證用戶 2)驗證地址 3)插入用戶 4)插入地址 5)如果有問題,請回滾所有內容 #### 3.16 始終在單個日志消息中包含有關異常的所有信息 ```java LOGGER.debug("Using cache sector A"); LOGGER.debug("Using retry sector B"); ``` 不要這樣 在測試用例中,將多行日志消息與多次調用`LOGGER.debug()`一起使用可能看起來不錯,但是當它顯示在并行運行 400 個線程的應用服務器的日志文件中時,所有信息都將轉儲到同一線程 日志文件中,即使兩條日志消息出現在代碼的后續行中,它們最終也可能在日志文件中以 1000 行隔開。 像這樣做: ```java LOGGER.debug("Using cache sector A, using retry sector B"); ``` #### 3.17 將所有相關信息傳遞給異常,以使它們盡可能多地提供信息 這對于使異常消息和棧跟蹤有用和提供信息也非常重要。 如果您無法從中確定任何內容,則日志的用途是什么。 這些類型的日志僅存在于您的代碼中用于裝飾。 #### 3.18 總是終止被中斷的線程 ```java while (true) { try { Thread.sleep(100000); } catch (InterruptedException e) {} //Don't do this doSomethingCool(); } ``` `InterruptedException`是您的代碼的線索,它應該停止正在執行的任何操作。 線程被中斷的一些常見用例是活動事務超時或線程池被關閉。 您的代碼應該盡最大努力完成正在執行的工作,并結束當前的執行線程,而不是忽略`InterruptedException`。 因此,請更正上面的示例: ```java while (true) { try { Thread.sleep(100000); } catch (InterruptedException e) { break; } } doSomethingCool(); ``` #### 3.19 使用模板方法重復`try-catch` 在代碼的 100 個地方沒有使用相似的`catch`塊是沒有用的。 它增加了代碼重復性,無濟于事。 在這種情況下,請使用模板方法。 例如,下面的代碼嘗試關閉數據庫連接。 ```java class DBUtil{ public static void closeConnection(Connection conn){ try{ conn.close(); } catch(Exception ex){ //Log Exception - Cannot close connection } } } ``` 這種類型的方法將在應用中的數千個位置中使用。 不要將整個代碼放在每個地方,而要定義上述方法,并在如下所示的任何地方使用它: ```java public void dataAccessCode() { Connection conn = null; try{ conn = getConnection(); .... } finally{ DBUtil.closeConnection(conn); } } ``` #### 3.20 使用 javadoc 記錄應用中的所有異常 練習 Javadoc 一段代碼在運行時可能拋出的所有異常。 還要嘗試包括可能的措施,如果出現這些異常,用戶應遵循。 我現在所想到的就是與 Java 異常處理最佳實踐相關的所有內容。 如果您發現任何缺失或與我的觀點無關,請給我評論。 我很樂意討論。 學習愉快!
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看