3秒でわかる
ファイルや接続の閉じ忘れを防ぐ Java の構文。丸括弧の中で開いた資源を、処理の成否にかかわらず自動的に close してくれます。
もう少し詳しく
どういうものか
try-with-resources は、try の直後の丸括弧の中で資源を宣言すると、ブロックを抜けるときにその資源の close() が自動で呼ばれる構文です。Java 7 で追加されました。対象になるのは AutoCloseable を実装した型で、ファイルの入出力、データベース接続、ソケットなどが該当します。
丸括弧の中には、セミコロン区切りで複数の資源を書けます。閉じられる順序は宣言と逆で、後に開いたものから閉じます。
なぜ必要か
以前は finally ブロックで close を呼んでいましたが、この書き方には落とし穴がありました。close 自体が例外を投げると、try の中で起きた本来の例外がその例外に上書きされ、原因が分からなくなります。null 判定も必要で、資源が 2 つあると入れ子が深くなります。
try-with-resources では、close が投げた例外は抑制された例外として本来の例外にぶら下がる形で保存されます。原因が消えず、記述量も大幅に減ります。
具体例
import java.io.*;
import java.sql.*;
public class Main {
void readFile() throws <a href="/glossary/ioexception" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">IOException</a> {
try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} // ここで br.close() が必ず呼ばれる
}
void query(Connection conn) throws SQLException {
String sql = "SELECT name FROM members WHERE points > ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, 100);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.println(rs.getString("name"));
}
}
}
}
}つまずきやすいところ
丸括弧の中で new を入れ子にすると、外側の生成に失敗したときに内側が閉じられません。上の readFile も厳密にはその形です。確実に閉じたい場合は、資源をそれぞれ別に宣言してセミコロンで並べます。
もう 1 つは、閉じてはいけないものを渡してしまうことです。System.out を try-with-resources に入れると標準出力が閉じられ、以降の出力が消えます。引数で受け取った Connection も、閉じる責任が呼び出し元にあるなら括弧の中に書きません。
似た用語との違い
finally は「必ず通したい任意の処理」を書く場所で、通信の後始末に限りません。try-with-resources は資源を閉じることに特化しており、両方を同じ try に併記することもできます。その場合、close が先に呼ばれてから finally が実行されます。
覚え方
「括弧の中で開いたものは、括弧を出るときに閉じる」。開閉を 1 か所で対にできるのが利点です。