PR

【Java】try-with-resources文の基本を1からわかりやすく

Java

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 (リソースの宣言) {
    // リソースを使った処理
} catch (例外クラス 変数) {
    // 例外発生時の処理
}
  1. try丸括弧 ( ) 内でリソースを宣言 する。
  2. リソースは AutoCloseable インタフェースを実装している必要がある。(例:BufferedReader, FileWriter, Connection など)
  3. try ブロックの処理が終了すると、自動的に close() メソッドが呼び出される
  4. catch ブロックを省略することも可能。(ただし、例外処理が不要な場合のみ)
  5. 複数のリソースを ; で区切って宣言できる
  • リソース解放のコードが不要
    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();
}

読み取り用と書き込み用の両方を一括で管理できます。複数のリソースが増えてもスッキリしたコードになります。

裏側の仕組み(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バージョン
CloseableIOExceptionファイルやストリーム処理Java 1.5
AutoCloseableException全般的なリソースJava 1.7
  • CloseableIOException をスローする想定なので、主に 入出力系(IO) に特化。
  • AutoCloseable はより汎用的で、どんなリソースでも自動で閉じたい時に使える。
  • CloseableAutoCloseable の一種と考えて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();
        }
    }
}
// 出力:
// リソース使ってるよ
// リソース閉じたよ
Q
try-with-resourcesはどういう仕組みでcloseしているの?
A

◆ 結論:実はコンパイル時に「finallyclose() を呼ぶコード」に変換されています。

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() でも例外が出たら、もとの例外に「抑制例外」として記録する
ThrowableException よりも広くキャッチして、エラーも含めたあらゆる異常を扱える
  • try-with-resources はコンパイル時に try-catch-finally に展開されている。
  • 複数の例外(処理中+クローズ時)もきちんと扱えるようになっている。
  • 実は「しっかりした例外処理」が自動で入ってるのが便利なポイント。

気になるなら、.classjavap -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-resourcestry-catch-finally
リソースの解放自動で close() を呼ぶfinally ブロックで手動で close() する必要がある
コードの簡潔さ短くてシンプルネストが深く、冗長
複数リソースの管理; で区切るだけfinally でそれぞれ null チェックしながら close() する必要あり
例外処理try のブロックを抜けると確実に close() されるfinally 内で close() による例外をキャッチする必要あり

FAQ どちらを使うべきか?

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のように複数のリソースをまとめて安全にクローズできるため、コーディング効率が大幅にアップします。

まとめ Java:try-with-resources文

  • リソースの自動クローズで手間を削減
    close()の呼び出し漏れや例外処理の複雑化を防げます。
  • 複数リソースも一気に管理
    ;で区切るだけでOK。コードがさらにシンプルに。
  • 例外の抑制機能
    複数例外が発生してもメインの例外が優先され、補足的な例外は抑制されます。

Java 7以降であれば標準で利用できる構文です。今でもJavaの現場で多く使われていますので、これを機にぜひマスターして、より快適な開発環境を整えていきましょう。

タイトルとURLをコピーしました