yohhoyの日記

技術的メモをしていきたい日記

汎用スコープガード in Java8

Java 8で導入されたラムダ式またはメソッド参照と、Java 7以降のtry-with-resources構文を組合せて、任意のオブジェクトに対するスコープガード処理を記述する方法。

// Java 7以降
class X implements AutoCloseable {
  // AutoCloseable#closeを実装したクラスが必要
  void close() { ... }
}

try (X obj = new X(...)) {
  // ...
}
// 上記スコープを抜けるときにobj.close()が呼ばれる
// Java 8以降:メソッド参照版
class X {
  // メソッドシグニチャが"void メソッド名()"であればOK
  void dispose() { ... }
}

X obj = new X(...);
try (AutoCloseable ac = obj::dispose) {
  // ...
} catch (Exception e) { ... }
// 上記スコープを抜けるときにobj.dispose()が呼ばれる
// Java 8以降:ラムダ式版
class X {
  int method(int a1) { ... }
}

X obj = new X(...);
// 注意:以降での変数objへの再代入は禁止!
try (AutoCloseable ac = () -> obj.method(42)) {
  // ...
} catch (Exception e) { ... }
// 上記スコープを抜けるときにobj.method(42)が呼ばれる

ラムダを用いた上記例では、ラムダ式中でキャプチャするローカル変数objを “実質的にfinal(effectively final)” とするため、変数定義以降での再代入を行ってはならない。(もしくは単にfinal X obj = ...;で変数定義する)

メモ:AutoCloseable#closeメソッドはthrows Exception指定がついているため、try-with-resources構文側にcatch (Exception e) { ... }が必須になり煩雑。下記のようなインタフェースを用意してAutoCloseable代用とすれば回避可能。

interface NoThrowCloseable extends AutoCloseable { void close(); }

関連URL