try-with-resources 文は、1 つ以上のリソースを宣言する try 文です。リソースは、プログラムでの使用が終わったら閉じられなければいけないオブジェクトです。try-with-resources 文は、文の終わりで各リソースが確実に閉じられるようにします。java.io.Closeable を実装しているすべてのオブジェクトも含め、java.lang.AutoCloseable インタフェースを実装しているオブジェクトはリソースとして使用できます。
次の例は、ファイルから最初の行を読み取ります。ファイルからデータを読み取るために BufferedReader のインスタンスを使用します。BufferedReader は、プログラムでの使用が終わったら閉じられなければいけないリソースです。
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
この例で、try-with-resources 文で宣言されているリソースは BufferedReader です。宣言文は try キーワードの直後の括弧内にあります。Java SE 7 以降では、クラス BufferedReader はインタフェース java.lang.AutoCloseable を実装しています。BufferedReader インスタンスは try-with-resource 文で宣言されているため、try 文が正常に終了したか、(メソッド BufferedReader.readLine が IOException をスローした結果として) 突然終了したかにかかわらず、このインスタンスは閉じられます。
Java SE 7 より前では、try 文が正常に終了したか突然終了したかにかかわらずリソースが確実に閉じられるようにするために、finally ブロックを使用できます。次の例では、try-with-resources 文の代わりに finally ブロックを使用しています。
static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
if (br != null) br.close();
}
}
ただし、この例では、readLine と close メソッドの両方が例外をスローした場合、メソッド readFirstLineFromFileWithFinallyBlock は finally ブロックからスローされた例外をスローします。try ブロックからスローされた例外は抑制されます。これに対し、readFirstLineFromFile の例では、try ブロックと try-with-resources 文の両方から例外がスローされた場合、メソッド readFirstLineFromFile は try ブロックからスローされた例外をスローします。try-with-resources ブロックからスローされた例外は抑制されます。Java SE 7 以降では、抑制された例外を取得できます。詳細は、「抑制された例外」を参照してください。
1 つの try-with-resources 文で 1 つ以上のリソースを宣言できます。次の例は、Zip ファイル zipFileName にパッケージ化されているファイルの名前を取得し、これらのファイル名を含むテキストファイルを作成します。
public static void writeToFileZipFileContents(String zipFileName, String outputFileName)
throws java.io.IOException {
java.nio.charset.Charset charset = java.nio.charset.Charset.forName("US-ASCII");
java.nio.file.Path outputFilePath = java.nio.file.Paths.get(outputFileName);
// Open zip file and create output file with try-with-resources statement
try (
java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName);
java.io.BufferedWriter writer = java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
) {
// Enumerate each entry
for (java.util.Enumeration entries = zf.entries(); entries.hasMoreElements();) {
// Get the entry name and write it to the output file
String newLine = System.getProperty("line.separator");
String zipEntryName = ((java.util.zip.ZipEntry)entries.nextElement()).getName() + newLine;
writer.write(zipEntryName, 0, zipEntryName.length());
}
}
}
この例で、try-with-resources 文には 2 つの宣言 ZipFile および BufferedWriter が含まれており、セミコロンで区切られています。その直後のコードブロックが正常に終了または例外によって終了した場合、BufferedWriter オブジェクトと ZipFile オブジェクトの close メソッドが、この順序で自動的に呼び出されます。リソースの close メソッドは、作成時とは逆の順序で呼び出されます。
次の例では try-with-resources 文を使用して、java.sql.Statement オブジェクトを自動的に閉じます。
public static void viewTable(Connection con) throws SQLException {
String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES";
try (Statement stmt = con.createStatement()) {
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
String coffeeName = rs.getString("COF_NAME");
int supplierID = rs.getInt("SUP_ID");
float price = rs.getFloat("PRICE");
int sales = rs.getInt("SALES");
int total = rs.getInt("TOTAL");
System.out.println(coffeeName + ", " + supplierID + ", " + price +
", " + sales + ", " + total);
}
} catch (SQLException e) {
JDBCTutorialUtilities.printSQLException(e);
}
}
この例で使用されているリソース java.sql.Statement は、JDBC 4.1 以降の API の一部です。
注:通常の try 文と同様に、try-with-resources 文には catch ブロックと finally ブロックを含めることができます。try-with-resources 文内の catch または finally ブロックは、宣言されているリソースが閉じられたあとで実行されます。
try-with-resources 文に関連付けられたコードブロックから例外がスローされる場合があります。writeToFileZipFileContents の例では、try ブロックからは例外が 1 つスローされる可能性があり、try-with-resources 文からは、ZipFile オブジェクトと BufferedWriter オブジェクトを閉じようとするときに最大 2 つの例外がスローされる可能性があります。try ブロックから例外が 1 つスローされ、try-with-resources 文から 1 つ以上の例外がスローされた場合、try-with-resources 文からスローされた例外は抑制され、ブロックからスローされた例外が writeToFileZipFileContents メソッドによってスローされます。これらの抑制された例外は、try ブロックからスローされた例外から Throwable.getSuppressed メソッドを呼び出すことで取得できます。
AutoCloseable または Closeable インタフェースを実装するクラスのリストについては、これらのインタフェースの Javadoc を参照してください。Closeable インタフェースは AutoCloseable インタフェースを拡張したものです。Closeable インタフェースの close メソッドは IOException 型の例外をスローし、AutoCloseable インタフェースの close メソッドは Exception 型の例外をスローします。その結果、AutoCloseable インタフェースのサブクラスでは close メソッドのこの動作をオーバーライドして、IOException などの専用化された例外をスローしたり、例外をまったくスローしないようにしたりできます。