try-with-resources 文は、1 つ以上のリソースを宣言する try 文です。リソースは、プログラムでの使用が終わったら閉じられなければいけないオブジェクトです。try-with-resources 文は、文の終わりで各リソースが確実に閉じられるようにします。java.io.Closeable を実装しているすべてのオブジェクトも含め、java.lang.AutoCloseable インタフェースを実装しているオブジェクトはリソースとして使用できます。

try-with-resources 文

AutoCloseable 実装クラスのコンストラクタ、一般的なインスタンスメソッド、 close メソッドにて例外を発生させたときにどういう挙動をするのか調べた。

リソースとなる AutoCloseable 実装クラスが発生させるすべての例外は catch ブロックで捕捉できることがわかった。

複数箇所で例外が発生した場合は「抑制された例外」として、 Throwable クラスの getSuppressed メソッドで取得できる。

サンプルコード。


import java.util.Arrays;

public class Sample{

  public static class SampleResource implements AutoCloseable{

    private boolean a;
    private boolean b;
    private boolean c;

    /**
     * @param a コンストラクタで例外を発生させる場合は true
     * @param b hoge メソッドで例外を発生させる場合は true
     * @param c close メソッドで例外を発生させる場合は true
     */
    public SampleResource(boolean a, boolean b, boolean c) throws Exception{
      System.out.println("The constructor was called.");
      this.a = a;
      this.b = b;
      this.c = c;
      if(a){
        throw new Exception("The constructor threw an exception.");
      }
    }

    public void hoge() throws Exception{
      System.out.println("The hoge method was called.");
      if(b){
        throw new Exception("The hoge method threw an exception.");
      }
    }

    /**
     * @override
     */
    public void close() throws Exception{
      System.out.println("The close method was called.");
      if(c){
        throw new Exception("The close method threw an exception.");
      }
    }
  }

  public static void main(String[] args){

    System.out.println("コンストラクタで例外を発生させる");
    try(SampleResource sr = new SampleResource(true, false, false)){
      sr.hoge();
    }catch(Exception e){
      System.out.println("catch: " + e.getMessage());
    }finally{
      System.out.println("finally");
    }
    System.out.println();

    System.out.println("hoge メソッドで例外を発生させる");
    try(SampleResource sr = new SampleResource(false, true, false)){
      sr.hoge();
    }catch(Exception e){
      System.out.println("catch: " + e.getMessage());
    }finally{
      System.out.println("finally");
    }
    System.out.println();

    System.out.println("close メソッドで例外を発生させる");
    try(SampleResource sr = new SampleResource(false, false, true)){
      sr.hoge();
    }catch(Exception e){
      System.out.println("catch: " + e.getMessage());
    }finally{
      System.out.println("finally");
    }
    System.out.println();

    System.out.println("hoge と close メソッドで例外を発生させる");
    try(SampleResource sr = new SampleResource(false, true, true)){
      sr.hoge();
    }catch(Exception e){
      System.out.println("catch: " + e.getMessage());
      Throwable[] tlist = e.getSuppressed();
      Arrays.asList(tlist).forEach(
        (t) -> System.out.println("抑制された例外:" + t.getMessage())
      );
    }finally{
      System.out.println("finally");
    }
    System.out.println();
  }
}

実行結果。


$ java Sample
コンストラクタで例外を発生させる
The constructor was called.
catch: The constructor threw an exception.
finally

hoge メソッドで例外を発生させる
The constructor was called.
The hoge method was called.
The close method was called.
catch: The hoge method threw an exception.
finally

close メソッドで例外を発生させる
The constructor was called.
The hoge method was called.
The close method was called.
catch: The close method threw an exception.
finally

hoge と close メソッドで例外を発生させる
The constructor was called.
The hoge method was called.
The close method was called.
catch: The hoge method threw an exception.
抑制された例外:The close method threw an exception.
finally

tags: java

Posted by NI-Lab. (@nilab)