歡迎訪問 陳同學(xué)博客原文
Exception-Handling Antipatterns Blog from Oracle Community
Exception management antipatterns from Java Peanuts
《反模式-危機中軟件做修、架構(gòu)和項目的重構(gòu)》by 宋銳 等譯
異常設(shè)計實踐 中有位讀者評論:又記錄日志又拋異常反模式設(shè)計卸勺。其實我并不知道反模式虫蝶,本文是對于反模式的學(xué)習(xí)整理庶骄,數(shù)據(jù)都來自參考資料馋艺。
先岔開主題潜的,BB兩個小點:
- 讀者的一個評論,有時卻能讓筆者受益良多媳拴,這也是交流帶來的好處,打破認(rèn)知的局限兆览。
- 對于知識的學(xué)習(xí)經(jīng)常是寫小學(xué)作文的 總-分-總 模式屈溉。先知曉概念,然后碎片學(xué)習(xí)抬探,最后整體總結(jié)子巾,通過一個個小知識點的積累,最終不斷豐富與深化自己知識框架驶睦。
關(guān)于反模式
設(shè)計模式的風(fēng)靡砰左,反映了軟件從業(yè)人員對改善行業(yè)質(zhì)量與標(biāo)準(zhǔn)的強烈愿望,因使用和創(chuàng)建可復(fù)用的設(shè)計模式而獲得成功的項目不斷增長场航,設(shè)計模式體驗了巨大的價值缠导。
設(shè)計模式通俗來說就是 套路,來源于實踐溉痢,反哺給實踐僻造。但實踐中,也常因?qū)⒃O(shè)計模式應(yīng)用于不適當(dāng)?shù)纳舷挛沫h(huán)境而導(dǎo)致許多問題孩饼。
反模式 利用實踐經(jīng)驗來定義經(jīng)常發(fā)生的錯誤髓削,讓你留意開發(fā)過程中潛在的各種陷阱與風(fēng)險。反模式描述了這些易錯場景的基本形式镀娶、可能帶來的負(fù)面影響立膛,提供了補救措施,并給這些場景定義了名稱梯码。
更多關(guān)于反模式的知識宝泵,可以閱讀《反模式-危機中軟件、架構(gòu)和項目的重構(gòu)》轩娶。
異常處理反模式
此處僅挑選幾個儿奶,更多請參考 Exception-Handling Antipatterns Blog
Log and Throw
下面是三個討厭的反模式,既打印日志又拋出異常鳄抒,這對于運維工程師來說簡直就是噩夢闯捎,因為一個問題產(chǎn)生了多種log信息椰弊。
例1:
catch (NoSuchMethodException e) { LOG.error("Blah", e); throw e; }
例2:
catch (NoSuchMethodException e) {
LOG.error("Blah", e); throw new MyServiceException("Blah", e);
}
例3:
catch (NoSuchMethodException e) {
e.printStackTrace(); throw new MyServiceException("Blah", e);
}
Throwing Exception
public void foo() throws Exception {}
直接拋出 異常基類 完全打破了 checked exeption 的目的瓤鼻,這樣做就是在向你的調(diào)用者宣布:我可能會干點壞事秉版,你悠著點。
Catching Exception
try { foo(); } catch (Exception e) { LOG.error("Foo failed", e); }
這是"私吞"異常的例子娱仔,也是異常處理中不可饒恕的 惡行沐飘,異常從此憑空消失,只有這條淹沒在日志汪洋中的傻乎乎的日志是唯一線索牲迫。
Destructive Wrapping
catch (NoSuchMethodException e) { throw new MyServiceException("Blah: " + e.getMessage()); }
這種破壞性包裝導(dǎo)致原始異常的stack trace丟失耐朴,出現(xiàn)異常時大家一起來抓瞎,再抓個實習(xí)生頂鍋盹憎。
Return null
下面三個例子都返回null值筛峭,除非特殊的業(yè)務(wù)場景需要返回null值,否則最好拋出異常陪每,讓調(diào)用者進(jìn)行處理影晓。
catch (NoSuchMethodException e) { LOG.error("Blah", e); return null; }
catch (NoSuchMethodException e) { e.printStackTrace(); return null; }
catch (NoSuchMethodException e) { return null; }
Throw from Within Finally
try { blah(); } finally { cleanUp(); }
如果 cleanUp() 永遠(yuǎn)不會拋異常倒還好,因為如果 blah() 出錯檩禾,將進(jìn)入 finnaly挂签,可一旦 cleanUp() 出錯,將丟失 blah() 中拋出的異常盼产,同時需要處理 finally 中的異常饵婆。
Relying on getCause()
catch (MyException e) { if (e.getCause() instanceof FooException) {}
依賴 getCause() 的代碼非常脆弱,這種方式不一定能捕獲到真正的異常戏售。推薦使用 Apache的 commons-lang 中的 ExceptionUtils.getRootCause() 來代替侨核。