封面:洛小汐
譯者:潘潘html
知彼知己,方能百戰不殆。java
本文總結了有關Java異常的十大常見問題。git
檢查型異常(checked) vs. 非檢查型異常(Unchecked)程序員
異常管理的最佳實踐箴言github
爲何在try代碼塊中聲明的變量不能在catch或者finally中被引用?api
爲何 Double.parseDouble(null) 和 Integer.parseInt(null) 拋出的異常不同呢?微信
Java中常用的運行時異常oracle
咱們能夠在同一個catch子句中捕獲多個異常嗎?框架
在 Java 中構造方法能拋出異常嗎?ide
在 final 代碼塊中拋出異常
try語句有return那麼finally還會執行嗎?
簡單來講,對於檢查型異常, 通常在 編譯期 就會被檢查到,因此咱們確定會提早在方法內進行捕獲處理,或者在方法頭部申明並拋出。而非檢查型異常,每每沒法提早預知,例如被除數是0、空指針等。檢查型異常特別重要,它會告訴那些調用你的接口的開發者們,如何提早預知並處理好這些可能發生的異常。
例如,IOException就是常見的檢查型異常,而 RuntimeException(運行時異常)就是非檢查型異常。在閱讀剩餘部分以前你或許能夠研讀這份 Java異常的層次結構圖。
若是能夠正確處理異常,則應將其捕獲並處理,不然應將其拋出。
看下面這段代碼,在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代碼塊中哪一個位置會引起異常, 頗有可能在聲明對象以前就引起了異常。對於這個特定的示例,是正確的。
它倆拋出的異常確實不一樣,但這是JDK的問題,當時開發這兩個接口的開發人員不是同一波,因此咱們不必去糾結這個問題。
Integer.parseInt(null); // throws java.lang.NumberFormatException: null Double.parseDouble(null); // throws java.lang.NullPointerException
這裏列舉一部分:
IllegalArgumentException
ArrayIndexOutOfBoundsException
在有些場景某個目標對象不知足咱們的預期,會用到這些異常,例以下面在 if 判斷語句中被使用:
if (obj == null) { throw new IllegalArgumentException("obj can not be null");
答案是固然能夠,不過若是在同一個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 都寫上,這也是繼承原則。
答案是固然能夠,構造方法僅是一種特殊方法而已。能夠參考這個示例。
下面這個寫法是合法的:
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(); } }
答案是確定會執行。
Java官方文檔描述:The finally block always executes when the try block exits
意思就是 」 只要存在try代碼塊,finally代碼塊就必定會執行 」 ,這種特性可讓程序員避免在try語句中使用return, continue或者break關鍵字而忽略了關閉相關資源的操做等。
不少時候會見到下面這種代碼寫法。容許的狀況下儘量捕獲異常而且進行處理,不知道爲何不少開發人員就是這麼幹?
try { ... } catch(Exception e) { e.printStackTrace(); }
忽略異常是一件很容易作到的事,雖然這種寫法很常見,但不必定是正確的寫法。
譯文完,因爲我的理解能力和知識寬度有限,譯文中存在失誤之處,還請見諒,歡迎指正。
BIU ~ 文章持續更新,微信搜索「潘潘和他的朋友們」第一時間閱讀,隨時有驚喜。本文會在 GitHub https://github.com/JavaWorld 收錄,熱騰騰的技術、框架、面經、解決方案,咱們都會以最美的姿式第一時間送達,歡迎 Star。