# try-with-resources
在块中可以声明一个或多个资源。程序完成后,会自动释放该资源。实现了 java.lang.AutoCloseable
(包括实现 java.io.Closeable
的所有对象)可以用来声明。
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br =
new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
2
3
4
5
6
在该示例中生命的资源是 BufferedReader
,声明语句出现在 try 后的括号中。
BufferedReader
在 jdk7+ 实现了 java.lang.AutoCloseable
接口。
因此可以在 try-with-resource
语句中声明,无论 try 语句是正常完成还是意外完成(BufferedReader.readLine 抛出 IOException),它都将被关闭。
在 jdk7 之前,可以使用 finally 块来确保资源是否关闭。
在 finally 块来确保资源是否关闭的话。try 块中出现异常会被抛出,并需要你捕获。
而使用 try-with-resource
语句,则异常会被屏蔽,可以不捕获异常,但是必须要抛出。
在 JDK7+ 版本中,可以检索屏蔽异常。请参阅 屏蔽异常 一节。
以下是声明多个资源,使用 try 同样需要你捕获
@Test
public void test() throws IOException {
writeToFileZipFileContents("xxx.zip","xx.zip");
}
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());
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
多个声明使用分号隔开,代码块终止时,无论是正常还是异常,将按照此顺序自动调用对象的 close
方法。
注意,资源的 close
方法与他们创建相反的顺序调用。
try-with-resources 和捕获异常示例
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);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 屏蔽异常
可通过 Throwable[] getSuppressed()
获得。添加的话用 addSuppressed(Throwable exception)
,这个函数一般是在 try-with-resources 语句中自动调用的。
下面是上面的示例被编译成的 class 文件。可以看到 try-with-resources 也就是一个语法糖被编译后还是使用 try、catch、finally 来处理的。最后抛出一个异常。
仔细看只有 finally 中关闭资源的异常被屏蔽了。var5.addSuppressed(var32);
而且也能获得屏蔽的异常列表。这样的话,就能解决又不丢失异常信息,又能捕获且传递被屏蔽的异常了。
public static void writeToFileZipFileContents(String zipFileName, String outputFileName) {
Charset charset = StandardCharsets.US_ASCII;
Path outputFilePath = Paths.get(outputFileName, new String[0]);
try {
ZipFile e = new ZipFile(zipFileName);
Throwable var5 = null;
try {
BufferedWriter writer = Files.newBufferedWriter(outputFilePath, charset, new OpenOption[0]);
Throwable var7 = null;
try {
Enumeration entries = e.entries();
while (entries.hasMoreElements()) {
String newLine = System.getProperty("line.separator");
String zipEntryName = ((ZipEntry) entries.nextElement()).getName() + newLine;
writer.write(zipEntryName, 0, zipEntryName.length());
}
} catch (Throwable var34) {
var7 = var34;
throw var34;
} finally {
if (writer != null) {
if (var7 != null) {
try {
writer.close();
} catch (Throwable var33) {
var7.addSuppressed(var33);
}
} else {
writer.close();
}
}
}
} catch (Throwable var36) {
var5 = var36;
throw var36;
} finally {
if (e != null) {
if (var5 != null) {
try {
e.close();
} catch (Throwable var32) {
var5.addSuppressed(var32);
}
} else {
e.close();
}
}
}
} catch (IOException var38) {
(new Throwable(var38)).addSuppressed(var38);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 实现 AutoCloseable 或 Closeable 接口的类
有关实现这些接口的类的列表,请参阅 AutoCloseable 和 Closeable 接口的 Javadoc 。
public interface AutoCloseable {
void close() throws Exception;
}
public interface Closeable extends AutoCloseable {
public void close() throws IOException;
}
2
3
4
5
6
Closeable 扩展 AutoCloseable 接口,并且复写了 close 方法。抛出了一个具体的 IO 异常。