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仍然可以使用 catchfinally 代码块 – 和传统的 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.