---
# System prepended metadata

title: Exception
tags: [Java]

---

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