[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後會被釋放。