【編者按】做者 Yegor Bugayenko 是 Teamed.io 的軟件架構師,熱衷於軟件質量研究和有效的項目管理方法探索。在本文中,Yegor 就**「異常被捕獲但並未從新拋出」**這個問題進行了深刻討論,並分享了一些建議。html
對異常只捕獲但並未從新拋出到底是 anti-pattern,仍是個普通並且很是流行的錯誤確實無從考究。但毫無疑問的是,在全部異常捕獲代碼中,它基本無處不在,正以下面這段代碼:java
try { stream.write(data); } catch (IOException ex) { ex.printStackTrace(); }
注意:下面的代碼並無反對。編程
try { stream.write('X'); } catch (IOException ex) { throw new IllegalStateException(ex); }
這叫作 exception chaining,是一個很是有效的構造。架構
那麼,捕獲異常並記錄究竟存在什麼樣的問題?首先,從宏觀着手,這裏正在談論的是面向對象編程——意味着須要處理的是對象。一個對象(準確的說,是它的類)應該是這個樣子:性能
final class Wire { private final OutputStream stream; Wire(final OutputStream stm) { this.stream = stm; } public void send(final int data) { try { this.stream.write(x); } catch (IOException ex) { ex.printStackTrace(); } } }
這裏這樣來應用這個類的:this
new Wire(stream).send(1);
看起來不錯,對麼?當調用 send(1)
時,並不須要擔憂出現 IOException
,它將在方法內部處理。同時,若是出現異常,異常信息會被記錄。可是這麼作的理念是徹底錯誤的,它傳承自沒有異常處理的語言,好比 C。設計
異常的發明是爲了將整個錯誤處理代碼從主要邏輯中移除,以此來簡化設計。同時,它們不只僅是被移走,並且被集中在一個地方——在 main()
方法中,即整個應用的入口。code
一個異常的主要目的是蒐集儘量多的錯誤信息並將它拋到最上層,在這裏用戶可以針對它作一些處理。Exception chaining 則能夠幫助更多,它容許在異常拋至上層的過程當中擴充錯誤信息。在這個過程當中,實際上很是相似於每次捕獲到泡泡(即異常)後,所作的只是將它添加到一個更大的泡泡中而後從新拋出。當它到達最高層的時候,那裏就有許多泡泡,像一個 Russian Doll,一個嵌套着另一個。最原始的異常就是最小的那個泡泡。htm
當捕獲一個異常而並無從新拋出時,等同於你捏碎了這個泡泡。其中包含的大量信息,包括最原始的異常和全部其它帶有信息的泡泡,都被你緊緊的抓在手中。你杜絕爲上層呈現它,同時你如何處理和使用上層也毫無察覺。這一切都像是暗箱操做,一些潛在的重要信息被隱藏。對象
所以,在這裏直接致使的是 send()
方法沒法獲得信任,一樣基於 send()
方法的操做也沒法獲得信任,對象之間的信任鏈被破壞殆盡。這裏的建議是儘量少捕獲異常,同時一旦捕獲則必須拋出。
不幸的是,Java 在不少地方的設計違背了這個原則。例如,Java 有需檢查和不需檢查的異常兩類,可是在我看來,只應該有需檢查的異常(這些異常必須被捕獲或者聲明爲 throwable)。並且,Java 容許在一個方法中將多個異常類型聲明爲 throwable ——這是另外一個錯誤;堅持只聲明一種類型。在層次結構的頂部有一個通用的 Exception
類,在我看來也是錯誤的。除此以外,一些內置的類不容許拋出任何需檢查的異常,好比說Runnable.run()
。Java 還有許多關於異常的問題。
可是嘗試記住這些原則,你的代碼將會更加整潔:catch
除非你別無選擇。
P.S.這個類應該是這個樣子:
final class Wire { private final OutputStream stream; Wire(final OutputStream stm) { this.stream = stm; } public void send(final int data) throws IOException { this.stream.write(x); } }
原文連接:Catch Me If You ... Can't Do Otherwise
本文系 OneAPM 工程師編譯整理。OneAPM 是應用性能管理領域的新興領軍企業,能幫助企業用戶和開發者輕鬆實現:緩慢的程序代碼和 SQL 語句的實時抓取。想閱讀更多技術文章,請訪問 OneAPM 官方博客。