[toc] https://docs.oracle.com/javase/tutorial/essential/exceptions/index.html # Exception ## introduction 當在方法執行時出了錯, 會生成一個`Exception`物件, 包含錯誤資訊 此舉也稱為"throws an exception" (丟擲例外)。 丟擲例外之後, 會嘗試在Call Stack(呼叫方法堆疊) 逆序尋找一個能處理`Exception`的exception handler。 如果找到能處理的, 就好了。 如果沒找到, 程序會結束。 `Exception`繼承自`java.lang.Throwable` (可丟擲) ### Error, Exception Throwable分成兩種: - Error: 比較不太會發生, 像是OutOfMemoryError,StackOverflowError - Exception: 在程式中比較常遇到, 像是NullPointerException,IOException 通常開發者不太需要處理Error,通常都是處理Exception ### Checked, Unchecked 其中, 又可以以另一種方法分為兩種, Check跟Unchecked: - Checked: 必須顯式處理的Exception, 在方法內要用try-catch處利, 否則要寫`throws` - Unchecked: 反之, 有`RuntimeException` 與 `Error` --- 繼承表 - Throwable: - Exception: - IOException - ... - ... - RuntimeException (Unchecked) - NullPointerException - ... - ... - Error: (Unchecked) - NoClassDefFoundError - OutOfMemoryError - ... - ... --- ## try catch 用`try`把可能會出錯的地方包起來, 再來可能會寫一些`catch` Block, 也就是exception handler. ```java try { // code } catch (ExceptionType ex) { } catch (ExceptionType ex) { } ``` 其中ExceptionType必須繼承自`Throwable` ### 使用一個Exception Handler catch 多種Exception ```java try { // code } catch (IOException | SQLException ex) { } ``` ## finally `try` block結束之後會執行`finally` block ```java try { // code } catch (ExceptionType ex) { } catch (ExceptionType ex) { } finally { } ``` --- Ex. 下面是把字串轉整數出錯的例子: Integer.parseInt有可能會丟擲NumberFormatException跟NullPointerException 但兩個都是Unchecked Exception, 可以不用寫try-catch 但是假設你是給使用者輸入字串, 就應該要try-catch一下了。 ```java= public static void main(String[] args) { String s = "hello"; try { int i = Integer.parseInt(s); System.out.println(i); } catch (NumberFormatException e) { //用java.lang.Throwable裡面的printStackTrace方法 //輸出這個Exception的stacktrace e.printStackTrace(); } } ``` 可以用多個catch處理不同的Exception(不能重複) : ```java= public static void main(String[] args) { String s = "hello"; try { int i = Integer.parseInt(s); System.out.println(i); } catch (NumberFormatException e) { e.printStackTrace(); } catch (NullPointerException e) { System.out.println("s cannot be null"); } } ``` 直接catch(Exception): ```java public static void main(String[] args) { String s = "hello"; try { int i = Integer.parseInt(s); System.out.println(i); } catch (Exception e) { // 直接抓取所有exception, 但請盡量避免 e.printStackTrace(); } } ``` ## throws 如果method內可能有exception會出現, 但是你不想要在此method處理, 可以使用 `throws Exception1, Exception2 ...` 把可能出現的例外丟給上層call stack處理。 如果Method內有未處理的checked exception, 則必須寫`throws` Ex. checked exception ```java= public static void main(String[] args) { try { connect("https://api.speedcubing.top"); } catch (IOException ex) { // } } public static void connect(String url) throws IOException { new URL(url).openConnection(); } ``` --- ## 自訂Exception 找一個Exception,然後extends他, 完事。 - extends Exeption來製作Checked Exception - extends RuntimeException來製作Unchecked Exception ```java= class NumberOutofRangeException extends RuntimeException { } class NumberChecker { public static void check(int i, int low, int high) { if(i < low || high < i) { throw new NumberOutofRangeException(); } } } public class Main { public static void main(String[] args) { int i = 20; NumberChecker.check(i, 100, 200); System.out.println(i); } } ``` ``` Exception in thread "main" org.example.NumberOutofRangeException at org.example.NumberChecker.check(Main.java:10) at org.example.Main.main(Main.java:18) ``` --- ## try-with-resources resource是指程式執行完後需要關閉的物件, 會實作`java.lang.AutoCloseable` ```java try (Statement statement = con.createStatement()) { ResultSet rs = statement.executeQuery(query); } ``` 上述範例, statement物件離開try block後會被釋放。