Skip to content

24.Try-with-resouece

1. 概述

Java 7 中引入的对资源 try-with-resources 的支持允许我们声明要在 try 块中使用的资源,并保证资源将在该块执行后关闭。

声明的资源需要实现自动关闭接口

2. 使用资源Try代码块

简而言之,要自动关闭,必须在 try 中声明和初始化资源:

try (PrintWriter writer = new PrintWriter(new File("test.txt"))) {
    writer.println("Hello World");
}

3. 用资源的try替换try-finally

使用新的“try资源”功能的简单而明显的方法是替换传统的冗长的“try-catch-finally”块。

让我们比较以下代码示例。

第一个是典型的try-catch-finally块:

java
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的新的超级简洁解决方案:

java
try (Scanner scanner = new Scanner(new File("test.txt"))) {
    while (scanner.hasNext()) {
        System.out.println(scanner.nextLine());
    }
} catch (FileNotFoundException fnfe) {
    fnfe.printStackTrace();
}

下面是进一步探索扫描程序类的位置。

4. 使用多个资源try-with-resources

我们可以在 try-with-resources 块中声明多个资源,方法是用分号分隔它们:

java
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. 具有自动关闭功能的自定义资源

若要构造将由 try-with-resources 块正确处理的自定义资源,该类应实现 Closeable 或 AutoCloseable 接口并重写 close 方法:

java
public class MyResource implements AutoCloseable {
    @Override
    public void close() throws Exception {
        System.out.println("Closed MyResource");
    }
}

6. 资源关闭顺序

首先定义/获取的资源将最后关闭。让我们看一下此行为的示例:

资源 1:

java
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:

java
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");
    }
}

使用:

java
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资源块仍然可以具有catchfinally块,其工作方式与传统的try块相同。

8. Java 9 – 有效的finally变量

在Java 9之前,我们只能在try-with-resources块中使用新变量:

java
try (Scanner scanner = new Scanner(new File("testRead.txt")); 
    PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) { 
    // omitted
}

如上所示,这在声明多个资源时尤其冗长。从 Java 9 开始,作为 JEP 213 的一部分,我们现在可以在资源try块中使用finally甚至有效的finally变量:

java
final Scanner scanner = new Scanner(new File("testRead.txt"));
PrintWriter writer = new PrintWriter(new File("testWrite.txt"))
try (scanner;writer) { 
    // omitted
}

简而言之,如果变量在第一次赋值后没有更改,即使它没有明确标记为 final,它实际上是 final

如上所示,scanner 变量被显式声明为 final,因此我们可以将其与 try-with-resources 块一起使用。尽管编写器变量不是显式 final,但它在第一次赋值后不会更改。因此,我们也可以使用编写器变量。

9. 结论

在本文中,我们讨论了如何使用 try-with-resources 以及如何用 try-with-resources 替换 trycatchfinally

我们还研究了使用 AutoCloseable 构建自定义资源以及资源的关闭顺序。

Released under the MIT License.