Javaでファイル操作やデータベース接続などを行う際は、そのファイルやデータベースへの接続は必ず解除=解放(close)する必要があります。それを実現するために、従来はtry-catch-finally(参考 Javaの例外処理)で行いたい処理に加えてclose処理をしっかり書かなければなりませんでしたが、Java 7から導入されたtry-with-resources構文を使えば、コードをシンプルにしつつ、安全な処理を実現することができます。
昔からあるシステムのコードではあまり見かけませんが、直近新規で開発されたシステムなどでは見るシーンも増えました。Java Silver試験でも出題される内容ですので、頭に入れておきたい基本知識の1つです。

このページではJava初心者向けに1からわかりやすくサンプルコード付きでご説明します。
try-with-resources文
try-with-resourcesは、tryブロックで宣言したリソースを自動的にclose()してくれる構文です。以下の特徴があります。
- リソース解放のコードが不要
tryブロックを抜けると、自動的にclose()が呼び出されます。 - コードがスッキリ
finallyブロックを書かなくても良いので、可読性が高まります。 - 複数リソースも一括管理
;で区切ってリソースを並べれば、すべて自動でクローズされます。
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
try( )の中でインスタンスを宣言するだけで、tryブロックを抜ける際に自動でclose()してくれます。以下のように複数のリソースを同時に使うような処理も記述可能です。
try (
BufferedReader br = new BufferedReader(new FileReader("input.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))
) {
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
読み取り用と書き込み用の両方を一括で管理できます。複数のリソースが増えてもスッキリしたコードになります。
try-with-resources の処理の順番
ここでは、try-with-resources の処理の順番にフォーカスして、「リソースの生成」から「close()の呼び出し」「catch」「finally」までを完全に時系列で解説します👇
try (リソースの宣言) {
// メインの処理
} catch (...) {
// エラー処理
} finally {
// 最後の処理
}
🪜 実行の順番は以下の通り。
| 順番 | 処理内容 |
|---|---|
| ① | try の括弧内でリソース(MyRes)を生成(上から順に) |
| ② | try ブロック内の処理を実行 |
| ③ | 例外が発生した場合、まずリソースの close() を逆順で呼ぶ |
| ④ | その後 catch ブロックが実行される |
| ⑤ | 最後に finally ブロックが実行される |
class MyRes implements AutoCloseable {
private String name;
MyRes(String name) {
this.name = name;
System.out.println(name + " を開く");
}
@Override
public void close() {
System.out.println(name + " を閉じる");
}
}
public class Main {
public static void main(String[] args) {
try (
MyRes r1 = new MyRes("リソース1");
MyRes r2 = new MyRes("リソース2");
) {
System.out.println("処理中");
throw new RuntimeException("エラー発生");
} catch (Exception e) {
System.out.println("catch: " + e.getMessage());
} finally {
System.out.println("finally");
}
}
}
/* 出力結果
リソース1 を開く
リソース2 を開く
処理中
リソース2 を閉じる
リソース1 を閉じる
catch: エラー発生
finally */
🔧 なぜこうなるか?
try-with-resourcesは、tryブロックの中で例外が出たら、catchより先にclose()を呼ぶ仕様です。- その理由は、catch内ではすでにリソースが閉じられている状態を保証したいから。
- これにより、catch内でリソース操作してエラーが出るのを防げます。
裏側の仕組み(AutoCloseableインタフェース)
try-with-resources構文では、AutoCloseableインタフェース(またはそのサブインタフェースであるCloseableなど)を実装したクラスのみが自動でクローズされます。
参考 インターフェースとは?
もし自作クラスで同じ仕組みを使いたい場合には、以下のようにAutoCloseableを実装する必要があります。これでtry-with-resourcesの括弧内に書くだけで、自動クローズ対象にできます。
class MyResource implements AutoCloseable {
@Override
public void close() throws Exception {
// リソース解放処理
}
}
リソースを自動で閉じたいなら AutoCloseable を実装する
念のため再度念押ししておくと、Javaの try-with-resources 文は、一言でいうと自動で close() を呼んでくれる構文です。そして、これを適切に使うにはそのクラスが AutoCloseable または Closeable を実装している必要があります。
◆ 詳細:2つのインターフェースの違いと使い分け
| インターフェース名 | close() の例外 | 主な用途 | Javaバージョン |
|---|---|---|---|
Closeable | IOException | ファイルやストリーム処理 | Java 1.5 |
AutoCloseable | Exception | 全般的なリソース | Java 1.7 |
CloseableはIOExceptionをスローする想定なので、主に 入出力系(IO) に特化。AutoCloseableはより汎用的で、どんなリソースでも自動で閉じたい時に使える。CloseableはAutoCloseableの一種と考えてOK。
class MyResource implements AutoCloseable {
public void doSomething() {
System.out.println("リソース使ってるよ");
}
@Override
public void close() {
System.out.println("リソース閉じたよ");
}
}
public class Main {
public static void main(String[] args) {
try (MyResource res = new MyResource()) {
res.doSomething();
}
}
}
// 出力:
// リソース使ってるよ
// リソース閉じたよ
- Qtry-with-resourcesはどういう仕組みでcloseしているの?
- A
◆ 結論:実はコンパイル時に「
finallyでclose()を呼ぶコード」に変換されています。try-with-resourcesは 構文上の糖衣構文(シンタックスシュガー) で、コンパイラが裏でfinallyによるclose()呼び出しに展開してくれています。
例えば次のコード:
try (MyResource res = new MyResource()) {
res.doSomething();
}
これはコンパイルされると、以下のような構造に変換されます:
MyResource res = new MyResource();
Throwable primaryException = null;
try {
res.doSomething();
} catch (Throwable t) {
primaryException = t;
throw t;
} finally {
if (res != null) {
if (primaryException != null) {
try {
res.close();
} catch (Throwable closeException) {
primaryException.addSuppressed(closeException);
}
} else {
res.close();
}
}
}
| ポイント | 説明 |
|---|---|
null チェック | 例外が出ても close() を呼ぶために必須 |
addSuppressed() | もし close() でも例外が出たら、もとの例外に「抑制例外」として記録する |
Throwable | Exception よりも広くキャッチして、エラーも含めたあらゆる異常を扱える |

try-with-resourcesはコンパイル時にtry-catch-finallyに展開されている。- 複数の例外(処理中+クローズ時)もきちんと扱えるようになっている。
- 実は「しっかりした例外処理」が自動で入ってるのが便利なポイント。
気になるなら、.class を javap -c で逆アセンブルしてみるのもおすすめです!
補足:try-with-resources は 自動で close() を「呼ぶ」だけ
Javaの try-with-resources は便利ですが、リソースの解放処理自体はあなた(開発者)が close() メソッド内に実装しないと意味がありません。
◆ 例:ちゃんと書かないと何も閉じられない
class MyResource implements AutoCloseable {
@Override
public void close() {
// ここにリソース解放処理を書かないとダメ
System.out.println("閉じました!");
}
}
もし close() の中が空だったら、「呼ばれてるけど何もしてない」状態になります。そのため、以下のようなメソッドを利用して必ずクローズする処理を記述しなければいけません。(この点、JavaSilverだけで勉強していると誤解しがちですので、注意が必要です。)
- ファイルを開いているなら →
fileStream.close() - DB接続なら →
connection.close() - スレッドやプロセスを使ってるなら →
shutdown()など
| 質問 | 答え |
|---|---|
close() は自動で呼ばれる? | はい。try-with-resources により自動で呼ばれます。 |
| 処理内容は書く必要ある? | 絶対に必要。何を閉じるかは自分で記述します。 |
| 書かなかったら? | 呼ばれるけど、何も起きません(リソースは解放されない)。 |
旧来の書き方との比較
try-catch-finallyの場合
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("test.txt"));
// ...
} catch (IOException e) {
// ...
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
// ...
}
}
}
try-with-resourcesの場合
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
// ...
} catch (IOException e) {
// ...
}
同じ処理内容でも、不要なクローズ処理が書かれなくて済むためスッキリ見えます。
ポイント try-with-resources と従来の方法の違い
| 比較項目 | try-with-resources | try-catch-finally |
|---|---|---|
| リソースの解放 | 自動で close() を呼ぶ | finally ブロックで手動で close() する必要がある |
| コードの簡潔さ | 短くてシンプル | ネストが深く、冗長 |
| 複数リソースの管理 | ; で区切るだけ | finally でそれぞれ null チェックしながら close() する必要あり |
| 例外処理 | try のブロックを抜けると確実に close() される | finally 内で close() による例外をキャッチする必要あり |
どちらを使うべきか?
✅ Java 7以降なら try-with-resources を推奨
→ AutoCloseable を実装しているリソースなら、明示的に close() する必要がないため、可読性・保守性が向上する。
✅ 古いバージョンのJava(6以前)を使う場合は try-catch-finally
→ Java 6以前では try-with-resources は使えないため、従来の方法を採用するしかない。
✅ AutoCloseable を実装していないカスタムリソースの場合
→ try-catch-finally を使うか、自作クラスを AutoCloseable に対応させる。
JDBCでの利用例
ファイル操作だけでなく、データベース操作でも非常に便利です。
try (
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/test", "user", "password");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM sample_table")
) {
while (rs.next()) {
System.out.println(rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}

Connection, Statement, ResultSetのように複数のリソースをまとめて安全にクローズできるため、コーディング効率が大幅にアップします。
