概要
1つ以上の「使い終わったらクローズする必要があるオブジェクト
」を受け取ったtry文のこと。
try(BufferedReader br = new BufferedReader(new FileReader(path))){
複数宣言の際は、宣言同士をセミコロン;
で区切る必要あり。
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)
- クローズ時処理をオーバーライドで実装
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句にて宣言しなければならない。
つまり、事前に宣言されていた変数を引数として渡したとしても、例外が発生する。
BufferedReader br = new BufferedReader(new FileReader(path));
try(br){
- Java9以降
事前に宣言済みである変数も、活用できるようになった。公式アップデート内容通知ページ
つまり先程のNG例のような記述でも、問題なく処理される。
ただし、変数が必ずtry-with-resources句内で宣言されるわけではなくなったことで、
final変数・実質的final変数、いずれでもない変数を対象として指定される可能性が出てきたが、その場合は例外が発生する。
BufferedReader br = null;
br = new BufferedReader(new FileReader(path))
try(br){
実質的final変数
final修飾されていないものの、初回代入以来一度も値が変更されていない変数のこと。
通常のtry文(finally句使用)との違い
- finally句でクローズ処理を記述したりする必要がなくなる
- より短く記述できるようになる他、クローズ処理記述忘れによるトラブルも抑止できる、というメリットがある。
- 例外が複数個所にて発生した場合の挙動が異なる
- 通常の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-with-resources句で発生した抑制例外は、try句よりスローされた例外で
- 通常のtry文
実行順序詳細
- 例外が発生しない場合
try句 → クローズ → finally句 - 例外が発生した場合
try句 → catch句 → クローズ → finally句
まとめ
try-with-resources文は、上記のような性質により、例外処理の信頼性・コードの可読性を向上させることができる。
ファイル操作・DB接続・ソケット通信など、明示的クローズが必須な処理を作成する際は、こちらを採用するとよいかもしれない。