1.概述
try-with-resources
是Java7中新增的异常处理机制 —— 它确保了语句执行完毕后会自动关闭使用的资源。
使用try-with-resource
机制,我们需要先在try()
中对资源进行声明,且申明的资源必须实现 AutoClosable
接口。
2. 使用 try-with-resources
简单来说,要实现资源自动关闭,必须在 try 内部声明和初始化资源,如下所示:
try (PrintWriter writer = new PrintWriter(new File("test.txt"))) {
writer.println("Hello World");
}
3. 用try-with-resources 替换传统的 try–catch-finally
try-with-resources
取代了传统冗长的 try-catch-finally
代码块,用起来更简单明了。
传统 try-catch-finally
方法:
Scanner scanner = null;
try {
scanner = new Scanner(new File("test.txt"));
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (scanner != null) {
scanner.close();
}
}
使用 try-with-resources
替换后代码更优雅简洁:
try (Scanner scanner = new Scanner(new File("test.txt"))) {
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
}
您可以进一步了解Scanner类。
4. try-with-resources 多个资源
try-with-resources 支持申明多个资源,以分号分隔:
try (Scanner scanner = new Scanner(new File("testRead.txt"));
PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
while (scanner.hasNext()) {
writer.print(scanner.nextLine());
}
}
5. 自定义资源实现 AutoCloseable接口
如果你有一个自定义资源,需要支持 try-with-resources ,那么该类应实现 Closeable 或 _AutoCloseable_接口,并重写 close 方法:
public class MyResource implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("Closed MyResource");
}
}
6. 资源关闭顺序
最先定义/获取的资源会被最后关闭,让我们看一个例子:
资源1:
public class AutoCloseableResourcesFirst implements AutoCloseable {
public AutoCloseableResourcesFirst() {
System.out.println("Constructor -> AutoCloseableResources_First");
}
public void doSomething() {
System.out.println("Something -> AutoCloseableResources_First");
}
@Override
public void close() throws Exception {
System.out.println("Closed AutoCloseableResources_First");
}
}
资源2:
public class AutoCloseableResourcesSecond implements AutoCloseable {
public AutoCloseableResourcesSecond() {
System.out.println("Constructor -> AutoCloseableResources_Second");
}
public void doSomething() {
System.out.println("Something -> AutoCloseableResources_Second");
}
@Override
public void close() throws Exception {
System.out.println("Closed AutoCloseableResources_Second");
}
}
使用:
private void orderOfClosingResources() throws Exception {
try (AutoCloseableResourcesFirst af = new AutoCloseableResourcesFirst();
AutoCloseableResourcesSecond as = new AutoCloseableResourcesSecond()) {
af.doSomething();
as.doSomething();
}
}
输出:
Constructor -> AutoCloseableResources_First
Constructor -> AutoCloseableResources_Second
Something -> AutoCloseableResources_First
Something -> AutoCloseableResources_Second
Closed AutoCloseableResources_Second
Closed AutoCloseableResources_First
7. catch & finally
使用 try-with-resources 后 仍然可以使用 catch 和 finally 代码块 – 和传统的 try 用法没什么区别.
8. Java 9: Effectively Final (等效Final)变量
Java 9之前, 在 try-with-resources中,我们只能new一个新的变量:
try (Scanner scanner = new Scanner(new File("testRead.txt"));
PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
// omitted
}
如上所示,特别在声明多个资源时,显得很冗长。 Java9后, 我们可以在try-with-resources中直接使用 final或者effectively final类型的变量:
final Scanner scanner = new Scanner(new File("testRead.txt"));
PrintWriter writer = new PrintWriter(new File("testWrite.txt"))
try (scanner;writer) {
// omitted
}
简单来说,effectively final 变量是指,即使一个变量未明确标记为_final_,但如果在第一次赋值后没有更改,则该变量实际上是 final 。
如上所示,scanner 变量被明确声明为 final ,因此我们可以将其与_try-with-resources_ 块一起使用。 虽然 writer 变量不是显式的 final ,但是因为首次赋值后并未更改。 因此,我们也可以使用 writer 变量。
9. 总结
在本文中,我们讨论了如何使用try-with-resources,如何用try-with-resources替换try -catch-finally,使用AutoCloseable构建自定义资源,以及关闭资源的先后顺序。
教程完整源代码存放在GitHub.