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 の規則
- try の丸かっこに書けるのは AutoCloseable を実装した型だけです。Closeable は AutoCloseable のサブインターフェースなので当然書けます
- リソース変数は暗黙に final です。try の中で別のオブジェクトを代入し直すことはできません
- close は自動で呼ばれます。catch も finally も省略できます。リソースを1つ以上書いた try は、catch も finally も無くてもコンパイルが通ります。ふつうの try では通りません
- close が呼ばれるのは、catch や finally が走る前です
4番が一番狙われます。try の中で例外が飛んだ場合、まず全部のリソースが逆順に閉じられ、そのあとで catch に入ります。
抑制された例外
try の中の例外と close の中の例外が同時に起きたら、生き残るのは try の中の例外です。close 側の例外は抑制された例外として脇に付き、getSuppressed で取り出せます。逆にはなりません。
AutoCloseable の close
AutoCloseable の close は throws Exception と宣言されていますが、実装する側は投げないなら throws を省けます。オーバーライドで例外を狭めるのは許されるからです。省いておくと呼び出し側が catch を書かずに済みます。
確かめる
演習では自作のリソースを2つ開き、通った順番を1本の文字列に記録します。close が逆順であること、そして例外が起きたときに close が catch より先に走ることを、実行結果で確認してください。
要件
- try-with-resources で Res を "A"、"B" の順に開く
- try の中で log に "body-" を足す
- n が 0 のときだけ IllegalStateException を投げる
- catch (IllegalStateException e) で "catch-" を足す
- finally で "finally" を足し、log.toString() を返す
入出力例
run(1) → "openA-openB-body-closeB-closeA-finally"
run(0) → "openA-openB-body-closeB-closeA-catch-finally"ヒント
編集 LuaGate編集部