try-with-resources 声明

原文: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

try -with-resources 语句是声明一个或多个资源的try语句。资源是一个在程序完成后必须关闭的对象。 try -with-resources 语句确保在语句结束时关闭每个资源。实现java.lang.AutoCloseable的任何对象(包括实现java.io.Closeable的所有对象)都可以用作资源。

以下示例从文件中读取第一行。它使用BufferedReader实例从文件中读取数据。 BufferedReader是程序完成后必须关闭的资源:

  1. static String readFirstLineFromFile(String path) throws IOException {
  2. try (BufferedReader br =
  3. new BufferedReader(new FileReader(path))) {
  4. return br.readLine();
  5. }
  6. }

在此示例中,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块来确保关闭资源。以下示例使用finally块而不是try -with-resources 语句:

  1. static String readFirstLineFromFileWithFinallyBlock(String path)
  2. throws IOException {
  3. BufferedReader br = new BufferedReader(new FileReader(path));
  4. try {
  5. return br.readLine();
  6. } finally {
  7. if (br != null) br.close();
  8. }
  9. }

但是,在此示例中,如果方法readLineclose都抛出异常,则方法readFirstLineFromFileWithFinallyBlock抛出从finally块抛出的异常;从try块抛出的异常被抑制。相反,在示例readFirstLineFromFile中,如果从try块和try -with-resources 语句抛出异常,则方法readFirstLineFromFile抛出从try块抛出的异常;从try -with-resources 块抛出的异常被抑制。在 Java SE 7 及更高版本中,您可以检索已抑制的异常;有关详细信息,请参阅禁止异常部分。

您可以在try -with-resources 语句中声明一个或多个资源。以下示例检索 zip 文件zipFileName中打包的文件的名称,并创建包含这些文件名称的文本文件:

  1. public static void writeToFileZipFileContents(String zipFileName,
  2. String outputFileName)
  3. throws java.io.IOException {
  4. java.nio.charset.Charset charset =
  5. java.nio.charset.StandardCharsets.US_ASCII;
  6. java.nio.file.Path outputFilePath =
  7. java.nio.file.Paths.get(outputFileName);
  8. // Open zip file and create output file with
  9. // try-with-resources statement
  10. try (
  11. java.util.zip.ZipFile zf =
  12. new java.util.zip.ZipFile(zipFileName);
  13. java.io.BufferedWriter writer =
  14. java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
  15. ) {
  16. // Enumerate each entry
  17. for (java.util.Enumeration entries =
  18. zf.entries(); entries.hasMoreElements();) {
  19. // Get the entry name and write it to the output file
  20. String newLine = System.getProperty("line.separator");
  21. String zipEntryName =
  22. ((java.util.zip.ZipEntry)entries.nextElement()).getName() +
  23. newLine;
  24. writer.write(zipEntryName, 0, zipEntryName.length());
  25. }
  26. }
  27. }

在此示例中,try -with-resources 语句包含两个以分号分隔的声明:ZipFileBufferedWriter。当直接跟随它的代码块正常或由于异常终止时,BufferedWriterZipFile对象的close方法将按此顺序自动调用。请注意,资源的close方法在它们创建的相反顺序中调用。

以下示例使用try -with-resources 语句自动关闭java.sql.Statement对象:

  1. public static void viewTable(Connection con) throws SQLException {
  2. String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES";
  3. try (Statement stmt = con.createStatement()) {
  4. ResultSet rs = stmt.executeQuery(query);
  5. while (rs.next()) {
  6. String coffeeName = rs.getString("COF_NAME");
  7. int supplierID = rs.getInt("SUP_ID");
  8. float price = rs.getFloat("PRICE");
  9. int sales = rs.getInt("SALES");
  10. int total = rs.getInt("TOTAL");
  11. System.out.println(coffeeName + ", " + supplierID + ", " +
  12. price + ", " + sales + ", " + total);
  13. }
  14. } catch (SQLException e) {
  15. JDBCTutorialUtilities.printSQLException(e);
  16. }
  17. }

此示例中使用的资源java.sql.Statement是 JDBC 4.1 及更高版本 API 的一部分。

try -with-resources 语句可以使catchfinally块像普通的try语句一样。在try -with-resources 语句中,任何catchfinally块在声明的资源关闭后运行。

可以从与try -with-resources 语句关联的代码块中抛出异常。在示例writeToFileZipFileContents中,可以从try块抛出异常,当try -with-resources 语句尝试关闭ZipFileBufferedWriter时,最多可以抛出两个异常。对象。如果从try块抛出异常并且从try -with-resources 语句抛出一个或多个异常,那么从try -with-resources 语句抛出的那些异常将被抑制,并抛出异常块是由writeToFileZipFileContents方法抛出的块。您可以通过从try块抛出的异常中调用Throwable.getSuppressed方法来检索这些抑制的异常。

实现 AutoCloseable 或 Closeable 接口的类

请参阅 AutoCloseableCloseable 接口的 Javadoc,以获取实现这些接口之一的类列表。 Closeable接口扩展了AutoCloseable接口。 Closeable接口的close方法抛出IOException类型的异常,而AutoCloseable接口的close方法抛出Exception类型的异常。因此,AutoCloseable接口的子类可以覆盖close方法的这种行为,以抛出专门的异常,例如IOException,或者根本没有异常。