java 如何忽略异常_java中如何解决异常
原文 | dzone.com/articles/9-…
作者 | Thorben Janssen
翻譯 | geekymv
無(wú)論你是初學(xué)者還是經(jīng)驗(yàn)豐富的開(kāi)發(fā)人員,對(duì)于你和你的團(tuán)隊(duì)來(lái)說(shuō),提高異常處理的能力可以更好的解決問(wèn)題。
Java中的異常處理并不是一件容易的事,初學(xué)者會(huì)覺(jué)得很難理解,即使是經(jīng)驗(yàn)豐富的開(kāi)發(fā)人員也可能需要花費(fèi)幾個(gè)小時(shí)來(lái)討論應(yīng)該如何拋出或處理哪些異常。
這也是為什么大多數(shù)開(kāi)發(fā)團(tuán)隊(duì)對(duì)于如何使用它們有自己的一套規(guī)則。如果你剛加入一個(gè)團(tuán)隊(duì),你可能會(huì)驚訝這些規(guī)則與你之前使用過(guò)的規(guī)則是多么的不同。
盡管如此,依然有一些最佳實(shí)踐在大多數(shù)團(tuán)隊(duì)中被使用。以下9個(gè)最重要的方法,可以幫助你開(kāi)始或提高異常處理。
1、在 finally 代碼塊中清理資源或使用 try-with-resource 語(yǔ)句
你經(jīng)常會(huì)在try代碼塊中使用一個(gè)資源,比如 InputStream,需要在之后關(guān)閉它。在這種情況下的一個(gè)常見(jiàn)錯(cuò)誤是在try塊的末尾關(guān)閉資源。
問(wèn)題是,只要沒(méi)有拋出異常這種方式可以很好的工作。try 代碼塊中的語(yǔ)句將被執(zhí)行,并且資源將被關(guān)閉。
但是你添加 try 代碼塊是有原因的,你調(diào)用一個(gè)或多個(gè)可能拋出異常的方法,或者可能是你自己拋出異常,這意味著你可能未到達(dá)try代碼塊的尾部,最終,你無(wú)法關(guān)閉資源。
因此,你應(yīng)該把所有清理代碼放在 finally 代碼塊中,或者使用 try-with-resource 語(yǔ)句。
使用 finally 代碼塊
與 try 代碼塊最后幾行不同,finally 代碼塊總是被執(zhí)行。這種情況發(fā)生在 try 代碼塊成功執(zhí)行之后,或者在catch 代碼塊中處理異常之后。因此,你可以確保清理了所有打開(kāi)的資源。
Java7 中的 Try-With-Resource 語(yǔ)句
另一種方式是 try-with-resource 語(yǔ)句,我在介紹Java異常處理一文中有更詳細(xì)的說(shuō)明。
如果你的資源實(shí)現(xiàn)了 AutoCloseable 接口,就可以使用它。這是大多數(shù) Java 標(biāo)準(zhǔn)資源所做的。當(dāng)你在 try 子句中打開(kāi)資源時(shí),它將在try 代碼塊執(zhí)行或者發(fā)生異常后自動(dòng)關(guān)閉。
2、首選具體的異常
拋出的異常越具體越好。請(qǐng)記住,一個(gè)不知道你的代碼的同事,也可能是幾個(gè)月以后的你,需要調(diào)用你的方法并處理異常。
因此,確保提供給他們盡可能多的信息。這使你的API更容易理解。最終,方法的調(diào)用者將能夠更好地處理異常或通過(guò)額外的檢查來(lái)避免異常。
因此,總是試著找到最合適你的異常事件的類,例如,拋出 NumberFormatException 而不是 IllegalArgumentException。避免拋出一個(gè)不具體的異常。
3、為指定的異常編寫文檔
無(wú)論什么時(shí)候你在方法簽名上指定一個(gè)異常時(shí),你都應(yīng)該在你的Javadoc中為其編寫文檔。這與之前的最佳實(shí)踐有同樣的目標(biāo):提供給調(diào)用者盡可能多的信息,以便他可以避免或者處理異常。
因此,確保在你的Javadoc中增加@throws 聲明,并且描述可能造成異常的情況。
4、拋出帶有描述性信息的異常
這個(gè)最佳實(shí)踐背后的思想和之前兩個(gè)類似,不同的是,你不用將信息提供給方法的調(diào)用者。每個(gè)需要了解記錄在日志文件或監(jiān)控工具中異常信息的人,都可以閱讀該異常信息。
因此,應(yīng)該盡可能準(zhǔn)確的描述問(wèn)題,并且提供最相關(guān)的信息以了解異常事件。
不要誤會(huì)我的意思,你不應(yīng)該寫一個(gè)文本段落,而是應(yīng)該用1-2兩個(gè)短句解釋異常的原因。這樣可以幫助你的運(yùn)維團(tuán)隊(duì)了解問(wèn)題的嚴(yán)重性,也可以使你更容易分析任何服務(wù)事件。
如果拋出一個(gè)具體的異常,它的類名將最可能已經(jīng)描述了錯(cuò)誤的種類。因此,你不需要提供很多額外的信息。一個(gè)好的例子是 NumberFormatException。當(dāng)你提供一個(gè)錯(cuò)誤的字符串格式時(shí),將由 java.lang.Long 類的構(gòu)造方法拋出 NumberFormatException 異常。
NumberFormatException?類的名字已經(jīng)告訴你問(wèn)題的種類。它的信息僅僅需要提供導(dǎo)致問(wèn)題的輸入字符串。如果異常類的名字不那么具有表現(xiàn)力,則需要在消息中提供必要的信息。
17:17:26,386ERROR TestExceptionHandling:52- java.lang.NumberFormatException: For input string:"xyz"
譯者注:可見(jiàn),給類取個(gè)好名字多么重要。
5、優(yōu)先捕獲最具體的異常
大多數(shù) IDE 都可以幫助你實(shí)現(xiàn)這個(gè)最佳實(shí)踐。 當(dāng)你嘗試捕獲不太具體的異常時(shí),它們會(huì)報(bào)告一個(gè)不可到達(dá)的代碼塊。
問(wèn)題在于,只有第一個(gè)與異常匹配的 catch 代碼塊才會(huì)被執(zhí)行。因此,如果你首先捕獲一個(gè) IllegalArgumentException 異常,你將不能到達(dá)應(yīng)該處理更具體的 NumberFormatException 異常的 catch 代碼塊。因?yàn)樗?IllegalArgumentException 類的子類。
總是首先捕獲最具體的異常,然后將不太具體的 catch 代碼塊添加到列表的尾部。
在下面的代碼片段中,你可以看到 try-catch 語(yǔ)句的例子,第一個(gè) catch 代碼塊處理所有 NumberFormatException 異常,并且第二個(gè) catch 代碼塊處理所有不屬于 NumberFormatException 的 IllegalArgumentException 異常。
6、不要捕獲 Throwable
Throwable 是所有 Exception 和 Error 類的父類。你可以在 catch 語(yǔ)句中使用它,但是你絕對(duì)不要這樣做!
如果你在 catch 語(yǔ)句中使用 Throwable,它不僅捕獲所有的 Exception,還將捕獲所有的 Error。
Error 是被 JVM 拋出的,它表示不能被應(yīng)用程序處理的嚴(yán)重問(wèn)題。典型的例子是 OutOfMemoryError 或 StackOverflowError,都是由應(yīng)用程序無(wú)法控制的情況引起的,并且無(wú)法處理。
因此,最好不要捕獲 Throwable,除非你絕對(duì)確信自己處于能夠或需要處理錯(cuò)誤的特殊情況下。
7、不要忽略異常
你是否曾經(jīng)分析過(guò)一個(gè)bug報(bào)告,其中只執(zhí)行了用例的第一部分?
這通常是由忽略異常引起的,開(kāi)發(fā)者可能很確信它從不會(huì)拋出,并且添加了不處理或不打印日志的 catch 代碼塊,當(dāng)你找到這個(gè)代碼塊的時(shí)候,你甚至可能發(fā)現(xiàn)一個(gè)著名的注釋“This will never happen”。
因此,請(qǐng)不要忽略異常。你不知道代碼在未來(lái)將如何被改變。有人可能會(huì)刪除阻止異常事件的驗(yàn)證,而沒(méi)有意識(shí)到這會(huì)造成問(wèn)題。或拋出異常的代碼被更改,現(xiàn)在拋出同一個(gè)類的多個(gè)異常,并且調(diào)用代碼并不能阻止所有這些異常。
你至少應(yīng)該寫一條日志信息,告訴每個(gè)人意想不到的事情剛剛發(fā)生了,需要有人來(lái)檢查它。
8、不要打印日志的同時(shí)拋出異常
這可能是列表中最經(jīng)常被忽略的最佳實(shí)踐。你可以在許多代碼段甚至庫(kù)中發(fā)現(xiàn)異常被捕獲、打印日志、并重新拋出。
記錄發(fā)生的異常,然后將其重新拋出,以便調(diào)用者可以適當(dāng)?shù)奶幚硭?#xff0c;這可能會(huì)很直觀。但是它將為同一異常寫入多個(gè)錯(cuò)誤信息。
17:44:28,945 ERROR TestExceptionHandling:65 - java.lang.NumberFormatException: For input string: "xyz"Exception in thread "main" java.lang.NumberFormatException: For input string: "xyz"at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:589)
at java.lang.Long.(Long.java:965)
at com.stackify.example.TestExceptionHandling.logAndThrowException(TestExceptionHandling.java:63)
at com.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58)
額外的消息也沒(méi)有增加任何信息。正如最佳實(shí)踐4中所述,異常信息應(yīng)該描述異常事件。堆棧跟蹤會(huì)告訴你在哪個(gè)類,方法和行中引發(fā)了異常。
如果你需要增加額外的信息,你應(yīng)該捕獲異常并且將其包裝在自定義異常中,但是請(qǐng)確保遵循最佳實(shí)踐9。
9、包裝異常而不使用它
有時(shí)最好是捕獲一個(gè)異常并將其包裝到自定義異常中。這樣異常的典型例子是應(yīng)用程序或框架的具體業(yè)務(wù)異常。這使你可以增加額外的信息,并且還可以對(duì)異常類實(shí)現(xiàn)特殊處理。
當(dāng)你這樣做的時(shí)候,確保將原始異常設(shè)置為原因(cause)。Exception 類提供了接收 Throwable 參數(shù)的具體構(gòu)造方法。否則,你會(huì)丟失堆棧跟蹤和原始異常的信息,這將使分析導(dǎo)致異常的事件變得困難。
總結(jié)
如你所見(jiàn),當(dāng)你拋出或捕獲異常的時(shí)候,你應(yīng)該考慮很多不同的事情。它們中大多數(shù)的目標(biāo)是提高代碼的可讀性或API的可用性。
異常通常是一種錯(cuò)誤處理機(jī)制,同時(shí)也是一種通信機(jī)制。因此,你應(yīng)該確保與你的同事討論你想要應(yīng)用的最佳實(shí)踐和規(guī)則,以便每個(gè)人都理解一般的概念,并以相同的方式使用它們。
作者:Geek_ymv
鏈接:https://juejin.cn/post/6909838417278959630
來(lái)源:掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
總結(jié)
以上是生活随笔為你收集整理的java 如何忽略异常_java中如何解决异常的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java textfield事件_[求助
- 下一篇: java 招聘需求_Java人员要具备哪