簡體   English   中英

異常處理的“切換”等價物

[英]“switch” equivalent for exception handling

這通常不是關於異常處理的問題,但它特別適用於某些框架的使用。 典型起點的幾個例子:

  • GWT: public void onFailure(Throwable caught)實現的AsyncCallback接口。
  • JAX-RS: public Response toResponse(E throwable)實現ExceptionMapper<E extends Throwable>接口。

上述兩種方法都接收Throwable的實例。 通常,我看到開發人員使用一個簡單的“if / else if”塊來區分處理邏輯:

// As specified by the AsyncCallback class of the GWT framework
public void onFailure(Throwable caught) {
    if (caught instanceof AnException) {
        // handle AnException
    } else if (caught instanceof AnotherException) {
        // handle AnotherException
    } else if (caught instanceof YetAnotherException) {
        // handle YetAnotherException
    } else if (caught instanceof ...) {
        // and so on...
    }
}

由於我不是“if / else if”塊的粉絲,出於多種原因,我想出了以下“模式”,它將“if / else if”塊轉換為“try / catch”塊,表現得好像它是一個“開關”塊:

public void onFailure(Throwable caught) {
    try {
        throw caught;
    } catch(AnException e1) {
        // handle AnException
    } catch(AnotherException e2) {
        // handle AnotherException
    } catch(YetAnotherException e3) {
        // handle YetAnotherException
    } catch(...) {
        // and so on...
    }
}

我的問題是: 是否有任何缺點 - 在性能,最佳實踐,代碼可讀性,一般安全性,或者我沒有考慮或注意到的任何其他方面 - 使用這種方法?

正常情況下使用異常來引導程序流是一種代碼味道,但這並不是你在這里所做的。 我認為你可以通過以下幾個原因來解決這個問題:

  1. 我們已經出於各種原因捕獲並重新拋出異常(例如,“捕獲,采取某些行動,傳播”)。 意圖有點不同,但在成本方面並沒有差別。

  2. 您已經承擔了至少拋出一次此異常的成本。 您可能已經承擔了拋出,抓住,包裹或重新拋出原因的成本。 填寫堆棧跟蹤的成本已經支付。 再一次重新拋出已經填充的異常並不會增加復雜性的順序。

  3. 您沒有使用異常來指導正常代碼路徑的流動。 你正在對一個錯誤作出反應,所以你已經走在了一條特殊的道路上,你應該很少(如果有的話)在這里結束。 如果這種模式效率低下,除非你遇到很多異常,否則幾乎沒有問題,在這種情況下,你會遇到更大的問題。 花時間優化您期望采取的路徑,而不是您沒有的路徑。

  4. 在美學上,很少有東西能讓我的皮膚像if/else if長鏈一樣爬行, 特別是當條件只是類型檢查時。 在我看來,你提出的建議更具可讀性。 擁有多個有序的catch子句很常見,因此結構大多是熟悉的。 try { throw e; } try { throw e; }前導可以是非正統的,但它是很容易推理。

在傳播Throwable時要小心謹慎。 一些錯誤,比如VirtualMachineError層次結構,表明某些事情已經發生了嚴重錯誤,應該允許它們運行。 其他人,比如InterruptedException ,會傳達有關原始線程狀態的信息,不應該在不同的線程上盲目地傳播它們。 有些像ThreadDeath一樣跨越兩個類別。

只有在拋出大量錯誤時,性能才有意義。 它不會影響成功案例中的表現。 存在如此多的錯誤將比處理它們所花費的時間更重要。

如果你調用一個本地方法,並拋出異常,那么使用catch塊來處理它就沒問題了。 這是相同的,但使用遠程方法。 這不是正常的控制流,因為在獲取方法之前已經從RPC調用中拋出異常,因此使用通常的異常處理結構是很好的。

編譯器可以執行一些檢查,例如檢查是否首先列出了最具體的異常,但是使用一般的Throwable類型會丟失某些類型的安全性。 由於框架,這是不可避免的。

對於這里的任何一個例子我都沒問題,因為它沒有太大的區別。

你展示的兩個代碼塊實際上非常相似:乍一看它們與我的眼睛都是相同的“形狀”。

並且值得注意的是if / else鏈實際上比try / catch版本更少的代碼行和更容易理解。

我不認為try / catch版本本身是錯誤的 ,但是當像這樣並排比較時,我沒有看到任何理由為什么它會更好

和所有其他條件相同, 毫無爭議的代碼總是比有爭議的代碼更好的:你永遠不希望你的代碼的讀者由您選擇如何做到這一點分心從的代碼做了。

暫無
暫無

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

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