Try-With-Resources パターン
CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 62/87。
ファイルストリームやデータベース接続などのリソースを扱う場合、終了時には必ずそれらを閉じなければなりません。そうしないと、メモリリークのリスクがあります。伝統的なアプローチでは finally ブロックを使用しますが、冗長でエラーが発生しやすいです。
Javaの try-with-resources 文は、ブロックが終了したときにリソースを自動的にクローズします。AutoCloseable インターフェースを実装するすべてのクラスは、この構文で使用できます。
// 従来のアプローチ - 冗長でリスクがある
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("file.txt"));
String line = reader.readLine();
} finally {
if (reader != null) {
reader.close(); // ここでも例外が発生する可能性があります!
}
}
// Try-with-resources - クリーンで安全
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line = reader.readLine();
} // ここで自動的にクローズされますセミコロンで区切ることで、複数のリソースを管理できます。これらは宣言とは逆の順序でクローズされます:
try (FileReader fr = new FileReader("input.txt");
BufferedReader br = new BufferedReader(fr)) {
// 両方のリソースを使用します
} // brが最初にクローズされ、次にfrがクローズされます独自の auto-closeable クラスを作成するには、AutoCloseable インターフェースとその唯一の close() メソッドを実装します:
public class DatabaseConnection implements AutoCloseable {
public DatabaseConnection() {
System.out.println("Connection opened");
}
@Override
public void close() {
System.out.println("Connection closed");
}
}このパターンは、処理中に例外が発生した場合でも、リソースが常に適切に解放されることを保証します。
チャレンジ
簡単try-with-resourcesの威力を実証するリソース管理システムを構築しましょう!接続とセッションの管理をシミュレートするカスタムのAutoCloseableクラスを作成し、それらが常に適切にクリーンアップされることを確認します。
コードは3つのファイルに分けて構成します:
Connection.java: データベース接続をシミュレートするクラスを作成します。ConnectionクラスはAutoCloseableを実装する必要があります。接続名(String)のためのプライベートフィールド、名前を受け取って[name] connection openedと出力するコンストラクタ、Executing on [name]: [sql]と出力するquery(String sql)メソッド、そして[name] connection closedと出力する必須のclose()メソッドが必要です。Session.java: ユーザーセッションをシミュレートする別のAutoCloseableクラスを作成します。SessionクラスもAutoCloseableを実装する必要があります。ユーザー名(String)のためのプライベートフィールド、ユーザー名を受け取ってSession started for [username]と出力するコンストラクタ、[username] performed: [action]と出力するperformAction(String action)メソッド、そしてSession ended for [username]と出力するclose()メソッドを含めてください。Main.java: リソース管理システムを完成させましょう!接続名、ユーザー名、実行するアクションの3つの入力を受け取ります。まず、単一のリソース管理を実演します。
=== Single Resource ===と出力し、次にtry-with-resourcesを使用して、指定された名前でConnectionを作成します。tryブロックの中で、query("SELECT * FROM users")を呼び出します。ブロックが終了すると、接続は自動的に閉じられるはずです。次に、複数のリソースを実演します。空行を出力し、その後に
=== Multiple Resources ===と出力します。try-with-resourcesを使用して、Connection(同じ名前を使用)とSession(ユーザー名を使用)の両方を、セミコロンで区切ってその順序で宣言します。tryブロックの中で、まず接続に対してquery("INSERT INTO logs")を呼び出し、次にセッションに対して入力されたアクションでperformActionを呼び出します。リソースが宣言の逆順で閉じられる様子を確認してください!
入力は、接続名(String)、ユーザー名(String)、アクション(String)の順で3つ受け取ります。
try-with-resourcesによって、明示的なcloseの呼び出しやfinallyブロックが不要になることに注目してください。例外が発生した場合でもリソースのクローズが保証され、複数のリソースは宣言とは逆の順序でクローズされます!
チートシート
try-with-resources 文は、ブロックが完了したときにリソースを自動的に閉じます。AutoCloseable を実装しているクラスであれば、どのようなクラスでも使用できます:
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line = reader.readLine();
} // ここで自動的に閉じられますセミコロンで区切ることで、複数のリソースを管理できます。これらは宣言された順序とは逆の順序で閉じられます:
try (FileReader fr = new FileReader("input.txt");
BufferedReader br = new BufferedReader(fr)) {
// 両方のリソースを使用する
} // br が最初に閉じられ、次に fr が閉じられますカスタムの auto-closeable クラスを作成するには、AutoCloseable インターフェースとその close() メソッドを実装します:
public class DatabaseConnection implements AutoCloseable {
public DatabaseConnection() {
System.out.println("Connection opened");
}
@Override
public void close() {
System.out.println("Connection closed");
}
}自分で試してみよう
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String connectionName = scanner.nextLine();
String username = scanner.nextLine();
String action = scanner.nextLine();
// === 単一のリソース ===
// TODO: ヘッダーを出力する
// TODO: try-with-resources を使用して Connection を作成する
// TODO: try ブロック内で query("SELECT * FROM users") を呼び出す
// === 複数のリソース ===
// TODO: 空行とヘッダーを出力する
// TODO: Connection と Session の両方で try-with-resources を使用する
// TODO: try ブロック内:
// - connection に対して query("INSERT INTO logs") を呼び出す
// - session に対して入力された action を引数に performAction を呼び出す
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4継承
継承の基本 (extends)super キーワードメソッドのオーバーライド (@Override)コンストラクタチェーンObject クラス単一継承と多段階継承なぜ多重継承ができないのかまとめ:従業員の階層構造