154.md 6.5 KB
Newer Older
W
init  
wizardforcel 已提交
1 2 3 4
# try-with-resources 声明

> 原文: [https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html](https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html)

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

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

W
wizardforcel 已提交
9
```java
W
init  
wizardforcel 已提交
10 11 12 13 14 15 16 17 18 19 20 21 22
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`块来确保关闭资源。以下示例使用`finally`块而不是`try` -with-resources 语句:

W
wizardforcel 已提交
23
```java
W
init  
wizardforcel 已提交
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
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 及更高版本中,您可以检索已抑制的异常;有关详细信息,请参阅[禁止异常](#suppressed-exceptions)部分。

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

W
wizardforcel 已提交
40
```java
W
init  
wizardforcel 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
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());
        }
    }
}

```

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

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

W
wizardforcel 已提交
78
```java
W
init  
wizardforcel 已提交
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
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 语句可以使`catch``finally`块像普通的`try`语句一样。在`try` -with-resources 语句中,任何`catch``finally`块在声明的资源关闭后运行。

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

## 实现 AutoCloseable 或 Closeable 接口的类

请参阅 [`AutoCloseable`](https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html)[`Closeable`](https://docs.oracle.com/javase/8/docs/api/java/io/Closeable.html) 接口的 Javadoc,以获取实现这些接口之一的类列表。 `Closeable`接口扩展了`AutoCloseable`接口。 `Closeable`接口的`close`方法抛出`IOException`类型的异常,而`AutoCloseable`接口的`close`方法抛出`Exception`类型的异常。因此,`AutoCloseable`接口的子类可以覆盖`close`方法的这种行为,以抛出专门的异常,例如`IOException`,或者根本没有异常。