try-with-resources文

## 概要
1つ以上の「`使い終わったらクローズする必要があるオブジェクト`」を受け取ったtry文のこと。

```java:例1（単独宣言時）
try(BufferedReader br = new BufferedReader(new FileReader(path))){
```

複数宣言の際は、宣言同士をセミコロン`;`で区切る必要あり。
```java:例2（複数宣言時）
try(
    java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName);
    java.io.BufferedWriter bw = java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
){
```

## 特徴
try-with-resources句（冒頭の()内の記述）で宣言されたインスタンスは、
try句内で例外が発生したか否か、catch句で例外が補足されたかどうかに関わらず、常にクローズされる。

クローズの際は、渡した順番と**逆の順序**で、処理が呼び出される。
例2の場合なら、BufferedWriterのcloseメソッド⇒ZipFileのcloseメソッド、の順となる。


## 使用上の注意①：対象のクラスについて
対象のクラスが、インタフェース`java.lang.AutoCloseable`を実装していないと、try-with-resources文に用いることはできないため注意。

実際には、以下のようなクラスがtry-with-resources文の対象としてよく用いられます。
- `BufferedReader` / `BufferedWriter` … テキストファイルの読み書き
- `FileInputStream` / `FileOutputStream` … バイナリファイルの読み書き
- `ZipFile` … ZIPファイル操作
- `Connection`, `Statement`, `ResultSet`（JDBC）… データベース操作
- `Files.newBufferedReader` / `newBufferedWriter`（NIO）… ファイル入出力

これらはいずれも `AutoCloseable` または `Closeable` を実装しており、
明示的なクローズ処理が必要なリソースです。

#### おまけ（try-with-resources文で利用できるカスタムクラス例）
- インタフェースの実装（implements AutoCloseable）
- クローズ時処理をオーバーライドで実装
```java
public class Main {
  public static void main(String[] args) {
    test t = null;
    t = new test("test1");
    try(t){
        t.doSomething();
    }catch(Exception e){
      e.printStackTrace();
    }
  }

  public static class test implements AutoCloseable{
    private final String name;
    test(String name){
        this.name = name;
        System.out.println(name + " created");
    }
    public void doSomething(){
      System.out.println(name + " doing something");
    }
    @Override
    public void close(){
      System.out.println(name + " closed");
    }
  }
}
```

## 使用上の注意②：対象の宣言について
Javaのバージョンにより、対象の宣言に制限が生まれる。
- Java7または8
try-with-resources句にて宣言しなければならない。
つまり、事前に宣言されていた変数を引数として渡したとしても、例外が発生する。
```java:NG例（in Java7または8）
BufferedReader br = new BufferedReader(new FileReader(path));
try(br){
```
- Java9以降
事前に宣言済みである変数も、活用できるようになった。[公式アップデート内容通知ページ](https://docs.oracle.com/en/java/javase/13/language/try-resources.html)
つまり先程のNG例のような記述でも、問題なく処理される。
ただし、変数が必ずtry-with-resources句内で宣言されるわけではなくなったことで、
final変数・実質的final変数、いずれでもない変数を対象として指定される可能性が出てきたが、その場合は例外が発生する。
```java:NG例（in Java9以降）
BufferedReader br = null;
br = new BufferedReader(new FileReader(path))
try(br){
```
> 実質的final変数
> final修飾されていないものの、初回代入以来一度も値が変更されていない変数のこと。

## 通常のtry文（finally句使用）との違い
- finally句でクローズ処理を記述したりする必要がなくなる
    - より短く記述できるようになる他、クローズ処理記述忘れによるトラブルも抑止できる、というメリットがある。

<br>

- 例外が複数個所にて発生した場合の挙動が異なる
    - 通常のtry文
    try句・finally句の両方において例外が発生した場合、finally句で発生した例外が優先され、try句で発生した例外は失われることがある。
    - try-with-resources文
    try-with-resource句とtry句の両方において例外が発生した場合、
    try句で発生した例外のみ **主例外（primary exception）** としてスローされ、
    try-with-resources句で発生した例外は **抑制例外（suppressed exception）** となりスローはされないものの、補助的に記録はされる。
        - try-with-resources句で発生した抑制例外は、try句よりスローされた例外で`Throwable.getSuppressed`メソッドを呼び出すことにより、取得することが可能。

## 実行順序詳細
- 例外が発生しない場合
try句 → クローズ → finally句
- 例外が発生した場合
try句 → catch句 → クローズ → finally句

## まとめ
try-with-resources文は、上記のような性質により、例外処理の信頼性・コードの可読性を向上させることができる。
ファイル操作・DB接続・ソケット通信など、明示的クローズが必須な処理を作成する際は、こちらを採用するとよいかもしれない。

<br>

## 参照
[try-with-resources文公式ドキュメント](https://docs.oracle.com/javase/jp/8/docs/technotes/guides/language/try-with-resources.html)