try-with-resources 语句

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

下面的示例从文件中读取第一行。它使用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.AutoCloseableinterface。由于BufferedReader实例是在try -with-resource 语句中声明的,因此无论try语句是正常完成还是突然完成(由于方法BufferedReader.readLine抛出IOException),都将关闭该实例。

在 Java SE 7 之前,您可以使用finally块来确保关闭资源,而不管try语句是正常完成还是突然完成。下面的示例使用finally块而不是try -with-resources 语句:

static String readFirstLineFromFileWithFinallyBlock(String path)
                                                     throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }
}

但是,在此示例中,如果方法readLineclose都引发异常,则方法readFirstLineFromFileWithFinallyBlock引发从finally块引发的异常;否则,方法readFirstLineFromFileWithFinallyBlock引发从finally块引发的异常。从try块引发的异常被抑制。相反,在示例readFirstLineFromFile中,如果try块和try -with-resources 语句都抛出了异常,则方法readFirstLineFromFile抛出从try块抛出的异常。从try -with-resources 块引发的异常被抑制。在 Java SE 7 和更高版本中,您可以检索抑制的异常。有关更多信息,请参见Suppressed Exceptions部分。

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

public static void writeToFileZipFileContents(String zipFileName,
                                           String outputFileName)
                                           throws java.io.IOException {

    java.nio.charset.Charset charset =
         java.nio.charset.StandardCharsets.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 语句包含两个用分号分隔的声明:ZipFileBufferedWriter。当紧随其后的代码块终止时,无论是正常还是由于异常而终止,BufferedWriterZipFile对象的close方法都将按此 Sequences 自动调用。请注意,资源的close方法是按照其创建的相反 Sequences 调用的。

下面的示例使用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 -with-resources 语句可以具有catchfinally块,就像普通的try语句一样。在trywith-resources 语句中,任何catchfinally块都在声明的资源关闭后运行。

Suppressed Exceptions

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

实现 AutoCloseable 或 Closeable interface的类

有关实现这些interface之一的类的列表,请参见AutoCloseableCloseableinterface的 Javadoc。 Closeableinterface扩展了AutoCloseableinterface。 Closeableinterface的close方法抛出IOException类型的异常,而AutoCloseableinterface的close方法抛出Exception类型的异常。因此,AutoCloseableinterface的子类可以覆盖close方法的此行为,以引发专门的异常,例如IOException,或者根本没有异常。