try-with-resources

このレッスンでできるようになること。try-with-resources で複数のリソースを開いたときに close が呼ばれる順番と、close と catch のどちらが先かを答えられるようになります。

まず予測してください

try (Res a = new Res("A"); Res b = new Res("B")) { System.out.println("body"); }

コンストラクタで open、close で close と出すとして、出力はどうなるでしょうか。答えは openA、openB、body、closeB、closeA の順です。close は宣言と逆の順に呼ばれます。あとから開いたものを先に閉じる、という積み木の考え方です。ここを宣言順と答えさせるのが定番です。

try-with-resources の規則

  1. try の丸かっこに書けるのは AutoCloseable を実装した型だけです。Closeable は AutoCloseable のサブインターフェースなので当然書けます
  2. リソース変数は暗黙に final です。try の中で別のオブジェクトを代入し直すことはできません
  3. close は自動で呼ばれます。catch も finally も省略できます。リソースを1つ以上書いた try は、catch も finally も無くてもコンパイルが通ります。ふつうの try では通りません
  4. close が呼ばれるのは、catch や finally が走るです

4番が一番狙われます。try の中で例外が飛んだ場合、まず全部のリソースが逆順に閉じられ、そのあとで catch に入ります。

抑制された例外

try の中の例外と close の中の例外が同時に起きたら、生き残るのは try の中の例外です。close 側の例外は抑制された例外として脇に付き、getSuppressed で取り出せます。逆にはなりません。

AutoCloseable の close

AutoCloseable の close は throws Exception と宣言されていますが、実装する側は投げないなら throws を省けます。オーバーライドで例外を狭めるのは許されるからです。省いておくと呼び出し側が catch を書かずに済みます。

確かめる

演習では自作のリソースを2つ開き、通った順番を1本の文字列に記録します。close が逆順であること、そして例外が起きたときに close が catch より先に走ることを、実行結果で確認してください。

要件

  1. try-with-resources で Res を "A"、"B" の順に開く
  2. try の中で log に "body-" を足す
  3. n が 0 のときだけ IllegalStateException を投げる
  4. catch (IllegalStateException e) で "catch-" を足す
  5. finally で "finally" を足し、log.toString() を返す

入出力例

run(1)"openA-openB-body-closeB-closeA-finally" run(0)"openA-openB-body-closeB-closeA-catch-finally"

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.java
学習モード

メモ

try-with-resources

⌘S で保存