Javaにおける例外の種類

## 例外には大きく分けて3種類ある
- エラー
- チェック例外
- 非チェック例外

```
java.lang.Throwable
    ┣━java.lang.Error
    ┗━java.lang.Exception
        ┗━java.lang.RuntimeException
```

### エラー（Java.lang.Error）
`java.lang.Error`を継承している。
**メモリ不足などプログラミングでどうしようもない物。**
主にハードウェアの面でどうにかする。

### チェック例外・検査例外（Java.lang.Exception）
`java.lang.Exception`を継承している

:::note alert
ただし`java.lang.RuntimeException`を継承しないもののみ
:::

```
java.lang.Exception
    ┣━java.lang.RuntimeException// <--これ以外
    ┗━java.lang.IOException
                    ：
```

**コンパイラからtry-catch文などでハンドリングを強制される例外。**
IO処理などでよく見る。
例外を自作するときは基本これを継承する。
~~java.lang.RuntimeExceptionを継承している~~

### 非チェック例外・非検査例外（java.lang.RuntimeException）
java.lang.RuntimeExceptionを継承している
```
java.lang.RuntimeException
    ┣━java.lang.NullPointerException
    ┃                ：
    ┗━java.lang.IndexOutOfException
        ┗━java.lang.ArrayIndexOutOfException
                        ：
```
NullPointerExceptionなど実行時になって初めて発生する例外。
ArrayIndexOutOfBoundsExceptionなどプログラミング時のミスで発生することが多い。

## 例外に関する用語
- 例外ハンドリング
- （例外を）投げる
- （例外を）キャッチする
- try-catch文
- try-with-resource文
- throw
- throws

### 例外ハンドリング
発生した例外を補足して対処を書くことをいう。

### （例外を）投げる・スローする
生成した例外やキャッチ（捕捉）した例外をより上位のメソッド・オブジェクトに再びthrowすることを「throw」になぞらえて「例外を投げる・スローする」と言う。

### （例外を）キャッチする
例外をtry-catch文のcatchでキャッチ（捕捉）することを言う。

### try-catch文
発生した例外を捕捉してその対処を書くための構文
例外が発生する可能性のあるメソッドをtry後の中カッコ内に書く。
発生した例外の内どれを捕捉するかをcatch後の丸カッコ内に書く。
例外への対処をcatch後の中カッコ内に書く。
例外の発生の有無に限らず必ず行う処理をfinally後の中カッコ内に書く。
```java
    public static List<String> fileReader(Path path){
        List<String> list;
        try{
            // 例外の発生しうる処理
            list = Files.readAllLines(path);
        }catch(IOException e){// キャッチ（捕捉）する例外
            // 例外が発生した時の処理
            e.printStackTrace();
            list = Collections.emptyList();
        }finally{
            // 必ず実行する処理
            Systeml.out.println("ファイル読込終了");
        }

        return list;
    }
```
### try-with-resource文
簡単に言うとtry-catch文の進化版。
IO処理などのtry-catch文で必要だったclose()やclose()が引き起こす可能性のある例外への対処を書かなくて済む。

try-catch文での書き方
```java
    public static void fileWriter(String text, Path path){
        FileOutputStream fos = null;
        OutputStreamWriter osw = null;
        BufferedWriter writer = null;

        try{// 例外の発生しうるメソッドを持ったオブジェクト
            fos = new FileOutputStream(dir + file1);
        	osw = new OutputStreamWriter(fos,charset);
        	writer = new BufferedWriter(osw);

            // 例外の発生しうる処理
            bw.write(text);
            bw.newLine();
        }catch(IOException e){// キャッチ（捕捉）する例外
            // 例外が発生した時の処理
            e.printStackTrace();
            System.out.println("書き込みに失敗しました");
        }finally{
            // 必ず実行する処理
            System.out.println("ファイル書込処理終了");
            if(fos != null){
                try{
                    fos.close();
                 }catch(IOException e){
                    e.printStackTrace();
                }
            }
            if(osw != null){
                try{
                    osw.close();
                 }catch(IOException e){
                    e.printStackTrace();
                }
            }
            if(writer != null){
                try{
                    writer.close();
                 }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
```
ファイル書込みや読込を行う際などにプログラムがファイルにアクセスするのを終了する処理（クローズ）を行う必要があるが、そのclose()メソッド自体が例外を発生する可能性がある為try-catch文で囲む必要があった。
またクローズするオブジェクトが例外の発生などによって生成されなかった時にNullPointerExceptionを発生させないためにif文でnullチェックもする必要がある。

try-with-resource文
```java
    public static void fileWriter(String text, Path path){
        try(// 例外の発生しうるメソッドを持ったオブジェクト
            FileOutputStream fos = new FileOutputStream(dir + file1);
        	OutputStreamWriter osw = new OutputStreamWriter(fos,charset);
        	BufferedWriter writer = new BufferedWriter(osw);
         ){
            // 例外の発生しうる処理
            bw.write(text);
            bw.newLine();
        }catch(IOException e){// キャッチ（捕捉）する例外
            // 例外が発生した時の処理
            e.printStackTrace();
            System.out.println("書き込みに失敗しました");
        }finally{
            // 必ず実行する処理
            System.out.println("ファイル書込処理終了");
        }
    }
```
ファイル書込みや読込を行う際などにプログラムがファイルにアクセスするのを終了する処理（クローズ）を行う必要があるオブジェクトをtry後の丸カッコ内で生成すると、try-catch-finallyを抜けたときに自動的にcloseを呼び出してクローズしてくれる。
おかげで実行する処理や例外への対処のみに専念できるほか、クローズ処理のし忘れも無くなる。
AutoClosableインターフェース又はClosableインターフェースを実装しているクラスならどれでもこの構文が使える。

### throw
例外をプログラマが自分で呼び出す時に使う。
例えばメソッドの引数に間違いがあるときにそれを知らせる為に明示的に発生させる時がある。
その時newを使って例外オブジェクトを生成しただけではどこにも通知されない。
throwを用いることでメソッドの呼び出し元に通知する事ができる。
```java
throw new IllegalArgumentException("引数が異なります");
```
### throws
メソッドが発生しうる例外をメソッド呼び出し元に通知すると共にその例外への対処を強制する。
throwsがあるメソッドを実行する時は必ずtry-catch文で囲む必要がある。
囲んでいないとコンパイルエラーが発生してコンパイル自体出来なくなることによって例外への対処を忘れずに済む。
例えばIO処理のメソッドであるFiles#readAllLines(Path)はIOExceptionが発生する可能性があり、その例外への対処を強制する為に以下の様に書いてある。
```java
public class Files {
    public static List<String> readAllLines(Path path) throws IOException {
        // 処理
    }
}
```
## 参考
- [19.1 例外の基本（try-catch文、チェック例外、非チェック例外、throw文、throws句、マルチキャッチ、finallyブロック、スタックトレースなど）～Java Basic編](https://qiita.com/KenyaSaitoh/items/99b64f1a1208bd6a4a1e)
- [例外はハンドリングする必要がある](https://zenn.dev/inabajunmr/articles/284bc56dacefc6)