1. 導入: なぜAutoCloseableが重要なのか
Javaの実務開発において、ファイル入出力やデータベース接続などの「外部リソース」の扱いは避けて通れません。もしクローズ処理を忘れると、メモリリークや接続枯渇といった深刻な障害を招きます。かつてはfinallyブロックで泥臭くnullチェックとclose処理を書いていましたが、Java 7以降はAutoCloseableとtry-with-resourcesを活用するのが定石です。本記事では、これらを活用した安全なエラーハンドリング手法を解説します。
2. 基礎知識: AutoCloseableと関連する仕組み
AutoCloseableは、close()メソッドを持つインターフェースです。これを実装したクラスは、try-with-resources文で管理できるようになります。
・try-with-resources: tryの横にカッコを書き、そこにリソースを宣言することで、ブロック終了時に自動的にclose()を呼び出す構文です。
・Exception階層: close()メソッドはExceptionをスローできるため、リソース解放時のエラーも適切に補足する必要があります。
・Multi-catch: 複数の例外を一つのcatchブロックで処理する構文で、コードの重複を減らします。
3. 実装/解決策: 安全なリソース管理のベストプラクティス
リソース管理で最も重要なのは、「例外が発生しても確実にクローズすること」と「クローズ時の例外を隠蔽しないこと」です。try-with-resourcesを使うと、メインの処理で発生した例外が優先され、close時の例外は「抑制された例外(Suppressed Exception)」として付加されるため、デバッグが容易になります。
4. サンプルプログラム
以下のコードは、独自のリソースクラスを作成し、複数の例外を適切にハンドリングする例です。
public class ResourceExample {
// AutoCloseableを実装したカスタムクラス
static class MyResource implements AutoCloseable {
public void doSomething() throws Exception {
System.out.println(“処理を実行中…”);
throw new Exception(“メイン処理の例外”);
}
@Override
public void close() throws Exception {
System.out.println(“リソースをクローズします。”);
throw new RuntimeException(“クローズ時の例外”);
}
}
public static void main(String[] args) {
// try-with-resourcesで宣言
try (MyResource res = new MyResource()) {
res.doSomething();
} catch (Exception | RuntimeException e) {
// Multi-catchで複数の例外をまとめて処理
System.err.println(“補足した例外: ” + e.getMessage());
// 抑制された例外を確認する(現場でのデバッグに有効)
for (Throwable suppressed : e.getSuppressed()) {
System.err.println(“抑制された例外: ” + suppressed.getMessage());
}
}
}
}
5. 応用・注意点: 現場で陥りやすい罠
・close()内での例外発生: close()メソッド内で例外を投げると、元の処理が成功していた場合、その例外が呼び出し元に伝播します。close()内では「クローズに失敗した」というログ出力に留め、ビジネスロジックを阻害しない設計を検討することも重要です。
・リソースの順序: 複数のリソースをtry-with-resourcesで宣言した場合、宣言した順序と逆の順序でcloseが呼び出されます。依存関係がある場合は注意が必要です。
・try-with-resourcesを使えないケース: ライブラリの制約などで古いAPIを使う必要がある場合、finallyブロックでのnullチェックを忘れないようにしましょう。しかし、現代のJava開発では、可能な限りAutoCloseableをラッパーとして作成し、try-with-resourcesで管理する設計にリファクタリングすることをお勧めします。

コメント