簡體   English   中英

使用嵌套異常是一種好習慣嗎?

[英]Is it a good practice to use nested exceptions?

這可能是一個廣泛的問題,不是那種風格,但我仍然希望得到一些提示或指導方針。

我一直在查看一些遺留代碼,並發現其中一部分具有嵌套3或4級異常的方法。
這被認為是正常的做法還是應該盡可能避免這種代碼風格? 如果應該避免,除了異常處理成本增加和可讀性降低之外還有哪些負面影響? 是否有通用的方法來重構代碼以避免這種情況?

我個人更喜歡以下意識形態

包裹異形異常

“外來”異常是Java API或第三方庫拋出的異常。 換句話說,您無法控制的異常。

最好捕獲所有異常異常並將它們包裝在適當的應用程序特定異常中。 將外來異常轉換為您自己的異常后,您可以按照自己喜歡的方式傳播該異常。

Rethrowing Checked Exceptions可以獲得凌亂

如果您的應用程序使用已檢查的異常,則重新拋出原始異常意味着重新拋出它的方法也必須聲明它。

越接近調用層次結構的頂部,將聲明拋出的異常越多。 除非你只是聲明所有方法都拋出異常。 但是,如果您這樣做,您也可以使用未經檢查的異常,因為您實際上並沒有從編譯器異常檢查中獲得任何好處。

這就是為什么我更喜歡捕獲非特定於應用程序的異常並將它們包裝在特定於應用程序的異常中 ,然后再將它們傳播到調用堆棧中。

包裝指南:發生異常的上下文可能與異常本身的位置一樣重要。 應用程序中的給定位置可以通過不同的執行路徑到達,並且如果發生錯誤,則執行路徑可以影響錯誤的嚴重性和原因。

如果在向調用堆棧中向上傳播異常時需要向異常添加上下文信息,則需要使用活動傳播。 換句話說,您需要在調用堆棧的路上在各個相關位置捕獲異常,並在重新拋出或包裝之前向其添加相關的上下文信息。

public void doSomething() throws SomeException{

    try{

        doSomethingThatCanThrowException();

    } catch (SomeException e){

       e.addContextInformation(“more info”);
       throw e;  //throw e, or wrap it – see next line.

       //throw new WrappingException(e, “more information”);

    } finally {
       //clean up – close open resources etc.
    }

}

異常處理往往是處理流控制的一種昂貴的方法(當然對於C#和Java)。

構造異常對象時,運行時會做很多工作 - 將堆棧跟蹤放在一起,找出處理異常的位置等等。

如果將流控制語句用於流控制,則不需要擴展內存和CPU資源的所有這些成本。

此外,還存在語義問題。 例外情況適用於特殊情況,而不適用於正常的流量控制。 應該使用異常處理來處理意外/異常情況,而不是正常的程序流,否則,未捕獲的異常會告訴您更少。

除了這兩個,還有其他人閱讀代碼的問題。 以這種方式使用異常並不是大多數程序員所期望的,因此可讀性以及代碼的可理解程度如何。 當人們看到“異常”時,人們會認為 - 發生了一些不好的事情,這種事情本來就不應該發生。 因此,以這種方式使用異常只是簡單的混淆。

請看下面的鏈接

異常處理:Java 1.4的常見問題和最佳實踐 - pdf

為什么不將異常用作常規控制流?

異常處理的最佳實踐

錯誤處理

Google Links先生

我一直在查看一些遺留代碼,並發現其中一部分具有嵌套3或4級異常的方法。

這被認為是正常的做法還是應該盡可能避免這種代碼風格?

這不是以這種方式處理異常的必要過程,因為它會增加您的應用程序開銷,直到您確實需要處理非常特定的異常(已檢查或Alien Exceptions),並且您可以忽略開銷以獲取處理該異常的特定信息。

如果應該避免,除了異常處理成本增加和可讀性降低之外還有哪些負面影響?

正如我所提到的,如果您不打算使用嵌套異常處理(向上層處理程序添加一些附加信息的拋出),您將無法獲得有關異常的具體信息,您可能/可能不會代表某些棘手的異常執行特定操作,但在嵌套的情況下,您可以通過處理特定情況來執行操作。

是否有通用的方法來重構代碼以避免這種情況?

如果你有一個很難實現的程序可以做你想要的並且沒有嚴重的錯誤,那么為了上帝的緣故,請不要管它! 當您需要修復錯誤或添加功能時,您將無情地重構您在工作中遇到的代碼。 覆蓋自定義異常處理程序中的異常類,並添加一些添加的功能來處理您的問題。

重寫方法不得拋出新的或更廣泛的已檢查異常,而不是重寫方法聲明的異常。 例如,聲明FileNotFoundException的方法不能被聲明SQLException,Exception或任何其他非運行時異常的方法覆蓋,除非它是FileNotFoundException的子類。

跳這將有助於你。

如果可能,不應將已檢查的異常傳播到堆棧或鏈接。 如果一個方法拋出一個已檢查的Exception,它的調用者應該處理它,如果調用者沒有處理它並將它傳播給它的調用者,那么整體復雜性就會增加。

在三層示例中:Dao,Service,Controller

DAO層將拋出DAOException服務層不應該向控制器公開DAOException,而應該拋出Controller應該處理的相關BuinessExceptions。

你應該廢除異常嵌套。 您應該首先避免鏈接異常,或者(有選擇地)解包然后重新拋出堆棧中的嵌套異常。

關於處理遺留代碼,我建議你看看有關這個主題的書: http//www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052你甚至不需要經歷整個預訂,看看目前關注你的事情。

另外一本關於良好實踐的好書是: http//www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/ref=sr_1_1?s= books&ie=UTF8&qid=1356340809&sr=1-1&keywords= clean +代碼

處理嵌套異常時的最佳方法是重構代碼並使用運行時而不是已檢查的異常,並在需要時處理這些異常。 這樣代碼更易讀,更易於維護。

它取決於業務邏輯。 你可以對那里的異常采取行動,或者你可以將它一直傳播給調用者,並將其留給調用者以進行他想要的操作。

例如,有許多第三方API,他們不處理異常,但他們從方法中拋出它,從而便於API用戶根據需要采取行動。

eq oracle JDBC驅動程序。 Driver.getConnection()拋出異常。 現在,調用者/ API用戶可以根據需要處理它。 可以只打印堆棧跟蹤,可以通知管理員詢問他的注意力,或者可以選擇只是默默地退出應用程序。

有兩種方法:

To generate a separate exception for each event.
To create a generic exception and describe what caused it 

第一種方法允許您編寫不同的代碼來處理不同的事件,但它需要您編寫大量的Exception類,在某些情況下它可能太多了。

第二種方法更簡潔,但卻難以處理不同的情況。

正如在編程中經常發生的那樣,最好的解決方案是在中間,在那里平衡生成單獨的異常並對其他情況使用一個例外。

在這種情況下,拇指規則可以是為要使用單獨代碼專門處理的異常生成單獨的Exception類。

與投擲什么類似, 我們也應該控制要捕獲的內容 我們可以為catch塊使用兩種方法:

所有人都有一個捕獲區。 例如:

catch (Throwable e) {
throw new CommandExecutorException(e);
}

每個例外的許多捕獲塊一個。 例如:

} catch (ClassCastException e1) {
 ...
} catch (FileNotFoundException e) {
... 
} catch (IOException e) {
...
}

第一種方法非常緊湊,但基本上在同一情況下對每個異常進行分組,它僅在所有異常被平等管理並執行相同操作的情況下才有用。 這種方法通常是不鼓勵的,因為它無法控制被捕獲的異常,有時會導致很難發現的嚴重錯誤。

第二種方法需要更多代碼行,但您可以根據發生的異常執行不同的操作。 這種方法更靈活,但在某些情況下由於異常處理會導致您的方法很長。

暫無
暫無

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

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