try-with-resourcesについて

try-with-resourcesステートメントは、1つ以上のリソースを宣言するtryステートメントです。
リソースは、プログラムが終了した後で閉じなければならないオブジェクトです。
try-with-resourcesステートメントは、各リソースがステートメントの最後に閉じられることを保証します。
java.lang.AutoCloseableを実装するオブジェクトは、java.io.Closeableを実装するすべてのオブジェクトを含み、リソースとして使用できます。

https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.htmlより引用

try-with-resources構文は、Java7より導入されたファイルなどの読み込み処理に必ずclose処理が伴う処理に対して、 大変簡潔な構文で確実にclose処理が実現できるtry,catch,finally構文の代替構文です。

try-with-resources構文を利用できるオブジェクトは、java.lang.AutoCloseableインターフェイスを実装したクラス、
java.io.Closeableインターフェイスを実装したクラスを利用する時のみ実行可能です。

try-with-resources構文

try-with-resources
try( 型 変数名 = java.lang.AutoCloseable又はjava.io.Closeableの実装クラスのインスタンス ) {

//例外の起こりえる処理

doAnythingOne();

doAnythingTwo();

doAnythingLast();

} catch ( 例外クラスA e ) {

//catch節

doSomethingA();

} catch ( 例外クラスB e ) {

//catch節

doSomethingB();

} finally {

//finally節 closeの処理は不要

}

try-with-resourcesのサンプル

前頁のサンプルと比較すると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の指針

try-with-resources構文の利用における私の指針について明記します。

  • Java7以上の開発であれば、使える箇所は全てtry-with-resourcesで記載する。
  • 但し、Java6以前の過去資産のハンドリングは現状を維持する。(改修する場合は、try-with-resourcesに統一する)
  • 共通チームがtry-with-resourcesの品質の高い実装例を製造し、開発チームに教育する。

サンプルのダウンロードと実行方法

  • java_sample16.zipファイルを「c:¥download¥java¥samples¥」に保存して下さい。
  • java_sample16.zipファイルを「c:¥projects」配下に展開して下さい。
  • コマンドプロンプトを起動して、「sample17.bat」を実行して下さい。
  • javac,jar,javaが実行されてJavaTryWithSampleが実行されます。
  • 「c:¥projects¥education¥logs」配下のログの実行結果を確認して下さい。
  • ※.コマンドプロンプトに例外が出力されます。(例外のサンプルのため)
  • Linux,Unix,iOSの方はバッチファイルはお手数ですが作成して下さい。改行コードが「CRLF」の点ご留意ください。