try-with-resourcesステートメントは、1つ以上のリソースを宣言するtryステートメントです。
https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.htmlより引用
リソースは、プログラムが終了した後で閉じなければならないオブジェクトです。
try-with-resourcesステートメントは、各リソースがステートメントの最後に閉じられることを保証します。
java.lang.AutoCloseableを実装するオブジェクトは、java.io.Closeableを実装するすべてのオブジェクトを含み、リソースとして使用できます。
try-with-resources構文は、Java7より導入されたファイルなどの読み込み処理に必ずclose処理が伴う処理に対して、 大変簡潔な構文で確実にclose処理が実現できるtry,catch,finally構文の代替構文です。
try-with-resources構文を利用できるオブジェクトは、java.lang.AutoCloseableインターフェイスを実装したクラス、
java.io.Closeableインターフェイスを実装したクラスを利用する時のみ実行可能です。
try( 型 変数名 = java.lang.AutoCloseable又はjava.io.Closeableの実装クラスのインスタンス ) {
//例外の起こりえる処理
doAnythingOne();
doAnythingTwo();
doAnythingLast();
} catch ( 例外クラスA e ) {
//catch節
doSomethingA();
} catch ( 例外クラスB e ) {
//catch節
doSomethingB();
} finally {
//finally節 closeの処理は不要
}
前頁のサンプルと比較するとclose処理の15行程度が割愛できました。
/**
* ファイルの読み込み処理をtry-with-resources形式で記述した例
* @param filePath 読み込むファイルのエラー
* @throws ファイルの読み込みエラー、対応していない文字コードエラー、ファイルclose時
*/
@Override
protected final void fileReadSample( String filePath ) throws ApplicationException {
log.info("STEP1 init Stream");
try (BufferedReader br = new BufferedReader(
new InputStreamReader ( new FileInputStream( filePath ) , JavaTrySample.FILE_ENCODING ) ) ) {
log.info("STEP2 loop start");
String line;
while ( ( line = br.readLine() ) != null ) {
System.out.println(line);
}
log.info("STEP3 try block end.");
} catch (FileNotFoundException e) {
log.log( Level.SEVERE , "指定されたファイル{0}が存在しません。" , new String[]{ filePath } );
log.log( Level.SEVERE , "例外内容:" , e );
throw new ApplicationException( e );
} catch (UnsupportedEncodingException e) {
String[] params = { filePath , JavaTrySample.FILE_ENCODING };
log.log( Level.SEVERE , "指定されたファイル{0}の文字コードが、{1}ではありません。" , params );
log.log( Level.SEVERE , "例外内容:" , e );
throw new ApplicationException( e );
} catch (IOException e) {
log.log( Level.SEVERE , "指定されたファイル{0}読取時に例外が発生しました。" , new String[] { filePath } );
log.log( Level.SEVERE , "例外内容:" , e );
throw new ApplicationException( e );
}
}
try-with-resources構文において、理解すべき一つの特性があります。
try ( 初期化処理 ){ //処理メイン }
構文において、処理メインで例外が発生し、初期化処理で定義したリソースをcloseします。
この時に、上記サンプルの例では、close処理の例外はエラーログに出力されません。
このような場合には、closeの例外は、Throwable.getSuppressedメソッドを利用して例外を取得します。
前サンプルのIOExceptionの節を以下のように変更します。
closeの例外も丁寧にログに出力する場合
} catch (IOException e) {
log.log( Level.SEVERE , "指定されたファイル{0}読取時に例外が発生しました。" , new String[] { filePath } );
for ( Throwable t : e.getSuppressed() ) {
log.log( Level.SEVERE , "例外内容:" , t );
}
//close処理は含まれない。但し上記内容で例外はエラーログに出力
throw new ApplicationException( e );
}
try-with-resources構文の利用における私の指針について明記します。