最常见的10种Java异常问题!
封面:洛小汐
譯者:潘潘
前言
本文總結了有關Java異常的十大常見問題。
目錄
檢查型異常(checked) vs. 非檢查型異常(Unchecked)
異常管理的最佳實踐箴言
為什么在try代碼塊中聲明的變量不能在catch或者finally中被引用?
為什么 Double.parseDouble(null) 和 Integer.parseInt(null) 拋出的異常不一樣呢?
Java中經常使用的運行時異常
我們可以在同一個catch子句中捕獲多個異常嗎?
在 Java 中構造方法能拋出異常嗎?
在 final 代碼塊中拋出異常
try語句有return那么finally還會執行嗎?
為何有些開發人員對異常置之不理?
1.檢查型異常(checked) vs 非檢查型異常(Unchecked)
簡單來說,對于檢查型異常, 一般在 編譯期 就會被檢查到,所以我們肯定會提前在方法內進行捕獲處理,或者在方法頭部申明并拋出。而非檢查型異常,往往無法提前預知,例如被除數是0、空指針等。檢查型異常特別重要,它會告訴那些調用你的接口的開發者們,如何提前預知并處理好這些可能發生的異常。
例如,IOException就是常見的檢查型異常,而 RuntimeException(運行時異常)就是非檢查型異常。在閱讀剩余部分之前你或許可以研讀這份Java異常的層次結構圖。
2.異常管理的最佳實踐箴言
如果可以正確處理異常,則應將其捕獲并處理,否則應將其拋出。
3. 為什么在try代碼塊中聲明的變量不能在catch或者finally中被引用?
看下面這段代碼,在try代碼塊中聲明的 String s 就不能在catch中被引用, 這段代碼在編譯期是通不過的。
try?{File?file?=?new?File("path");FileInputStream?fis?=?new?FileInputStream(file);String?s?=?"inside"; }?catch?(FileNotFoundException?e)?{e.printStackTrace();System.out.println(s); }原因是你不知道在try代碼塊中哪個位置會引發異常, 很有可能在聲明對象之前就引發了異常。對于這個特定的示例,是正確的。
4.為什么 Double.parseDouble(null) 和 Integer.parseInt(null) 拋出的異常不一樣呢?
它倆拋出的異常確實不同,但這是JDK的問題,當時開發這兩個接口的開發人員不是同一波,所以我們沒必要去糾結這個問題。
Integer.parseInt(null);? //?throws?java.lang.NumberFormatException:?null?Double.parseDouble(null);? //?throws?java.lang.NullPointerException5.Java中經常使用的運行時異常
這里列舉一部分:
IllegalArgumentException ArrayIndexOutOfBoundsException
在有些場景某個目標對象不滿足我們的預期,會用到這些異常,例如下面在 if 判斷語句中被使用:
if?(obj?==?null)?{throw?new?IllegalArgumentException("obj?can?not?be?null");6.我們可以在同一個catch子句中捕獲多個異常嗎?
答案是當然可以,不過如果在同一個catch子句中捕獲的這些異常都直接或間接繼承自同一父類,那么就只能在catch子句中捕獲父類了。
//?Java?7?之前需要這樣 catch?(AException?a)?{logger.error(a);throw?new?MyException("a"); catch?(BException?b)?{logger.error(b);throw?new?MyException("b"); }catch?(CException?c)?{logger.error(c);throw?new?MyException("c"); }//?在Java?7中,可以捕獲所有這些異常? catch(AException?|?BException?|?CException?ex){logger.error(ex);throw?new?MyException(ex); }補充說明 : 其實是這樣,在 Java7 就開始支持catch子句捕獲多個異常,多個異常使用 XOR符號(I) 連接,異常的發生有可能是 A | B,但不能同時出現,相當于這些異常不能是間接或直接繼承自同一個父類,因為如果AB都繼承同一父類,那就不能 A|B 都寫上,這也是繼承原則。
7.在 Java 中構造方法能拋出異常嗎?
答案是當然可以,構造方法僅是一種特殊方法而已。可以參考這個示例。
class?FileReader{public?FileInputStream?fis?=?null;public?FileReader()?throws?IOException{File?dir?=?new?File(".");//get?current?directoryFile?fin?=?new?File(dir.getCanonicalPath()?+?File.separator?+?"not-existing-file.txt");fis?=?new?FileInputStream(fin);} }8.在 final 代碼塊中拋出異常
下面這個寫法是合法的:
public?static?void?main(String[]?args)?{File?file1?=?new?File("path1");File?file2?=?new?File("path2");try?{FileInputStream?fis?=?new?FileInputStream(file1);}?catch?(FileNotFoundException?e)?{e.printStackTrace();}?finally?{try?{FileInputStream?fis?=?new?FileInputStream(file2);}?catch?(FileNotFoundException?e)?{e.printStackTrace();}} }但是為了獲得更好的代碼可讀性,你應該將把 try-catch代碼塊封裝成一個新方法,然后將方法調用放在finally子句中:
public?static?void?main(String[]?args)?{File?file1?=?new?File("path1");File?file2?=?new?File("path2");try?{FileInputStream?fis?=?new?FileInputStream(file1);}?catch?(FileNotFoundException?e)?{e.printStackTrace();}?finally?{//?封裝方法methodThrowException();?} }9.try語句有return那么finally還會執行嗎?
答案是肯定會執行。
Java官方文檔描述:The finally block always executes when the try block exits
意思就是 ” 只要存在try代碼塊,finally代碼塊就一定會執行 ” ,這種特性可以讓程序員避免在try語句中使用return, continue或者break關鍵字而忽略了關閉相關資源的操作等。
10.為何有些開發人員對異常置之不理?
很多時候會見到下面這種代碼寫法。允許的情況下盡可能捕獲異常并且進行處理,不知道為什么很多開發人員就是這么干?
try?{... }?catch(Exception?e)?{e.printStackTrace(); }忽略異常是一件很容易做到的事,雖然這種寫法很常見,但不一定是正確的寫法。
參考文獻:
Unchecked exceptions in Java
The root of Java exception class hierarchy
Java exceptions related questions in stackoverflow
譯文完,由于個人理解能力和知識寬度有限,譯文中存在失誤之處,還請見諒,歡迎指正。
往期推薦SpringBoot接口冪等性實現的4種方案!
try-catch-finally中的4個巨坑,老程序員也搞不定!
對象復制的7種方法,還是Spring的最好用!
關注我,每天陪你進步一點點!
總結
以上是生活随笔為你收集整理的最常见的10种Java异常问题!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Zookeeper 的 5 大核心知识点
- 下一篇: Python中的Dask数组