Try with Resources

1. 概述

从Java 7开始,Java支持使用带有资源的try(Try with Resources),允许我们声明要在try块中使用的资源,并保证在该块执行后关闭该资源。

声明的资源必须实现AutoCloseable接口。

 

2. 使用try-with-resources

简单地说,要自动关闭资源,必须在try中声明和初始化资源,如下所示:

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

 

3. 用try-with-resources替换try-catch-finally

使用新的try-with-resources功能的简单而明显的方法是用它来替换传统而冗长try-catch-finally块。

让我们比较以下代码示例–首先是典型的try-catch-finally块,然后是使用等效try-with-resources块的新方法:

 1 Scanner scanner = null;
 2 try {
 3     scanner = new Scanner(new File("test.txt"));
 4     while (scanner.hasNext()) {
 5         System.out.println(scanner.nextLine());
 6     }
 7 } catch (FileNotFoundException e) {
 8     e.printStackTrace();
 9 } finally {
10     if (scanner != null) {
11         scanner.close();
12     }
13 }

 

下面是使用try-with-resources的超级简洁解决方案:

1 try (Scanner scanner = new Scanner(new File("test.txt"))) {
2     while (scanner.hasNext()) {
3         System.out.println(scanner.nextLine());
4     }
5 } catch (FileNotFoundException fnfe) {
6     fnfe.printStackTrace();
7 }

 

4. 用try-with-resources声明多个资源

多个资源可以在try-with-resources块中声明,用分号将它们分开:

1 try (Scanner scanner = new Scanner(new File("testRead.txt"));
2     PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
3     while (scanner.hasNext()) {
4     writer.print(scanner.nextLine());
5     }
6 }

 

5. 自定义一个可以自动关闭的资源类

要构造一个能被try-with-resources块正确处理的自定义资源,类应该实现CloseableAutoCloseable接口,并重写close方法:

1 public class MyResource implements AutoCloseable {
2     @Override
3     public void close() throws Exception {
4         System.out.println("Closed MyResource");
5     }
6 }

 

6. 资源关闭顺序

首先被定义或获取的资源将最后关闭;让我们看一个示例:

资源1:

 1 public class AutoCloseableResourcesFirst implements AutoCloseable {
 2  
 3     public AutoCloseableResourcesFirst() {
 4         System.out.println("Constructor -> AutoCloseableResources_First");
 5     }
 6  
 7     public void doSomething() {
 8         System.out.println("Something -> AutoCloseableResources_First");
 9     }
10  
11     @Override
12     public void close() throws Exception {
13         System.out.println("Closed AutoCloseableResources_First");
14     }
15 }

 

资源2:

 1 public class AutoCloseableResourcesSecond implements AutoCloseable {
 2  
 3     public AutoCloseableResourcesSecond() {
 4         System.out.println("Constructor -> AutoCloseableResources_Second");
 5     }
 6  
 7     public void doSomething() {
 8         System.out.println("Something -> AutoCloseableResources_Second");
 9     }
10  
11     @Override
12     public void close() throws Exception {
13         System.out.println("Closed AutoCloseableResources_Second");
14     }
15 }

 

运行代码:

1 private void orderOfClosingResources() throws Exception {
2     try (AutoCloseableResourcesFirst af = new AutoCloseableResourcesFirst();
3         AutoCloseableResourcesSecond as = new AutoCloseableResourcesSecond()) {
4  
5         af.doSomething();
6         as.doSomething();
7     }
8 }

 

输出:

1 Constructor -> AutoCloseableResources_First
2 Constructor -> AutoCloseableResources_Second
3 Something -> AutoCloseableResources_First
4 Something -> AutoCloseableResources_Second
5 Closed AutoCloseableResources_Second
6 Closed AutoCloseableResources_First

 

7. catch & finally

一个 try-with-resources 块仍然可以有 catch 和 finally 块,这与传统 try 块的工作方式相同。

 

8. Java 9: 有效最终变量(Effectively Final Variables)

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

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

 

如上所示,当声明多个资源时,这尤其冗长。作为Java 9和JEP 213的一部分,我们现在可以在try-with-resources块中使用final变量和有效最终变量(Effectively Final Variables)

1 final Scanner scanner = new Scanner(new File("testRead.txt"));
2 PrintWriter writer = new PrintWriter(new File("testWrite.txt"))
3 try (scanner;writer) { 
4     // omitted
5 }

 

简单地说,如果变量在第一次赋值之后没有改变,那么它实际上就是final(有效最终变量),即使它没有显式地标记为final

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

 

9. 题外话

在使用锁的时候,不要使用try-with-resources 语句。首先,解锁的方法名不是close。其次,即使将它重命名,try-with-resources 也无法正常工作。try-with-resources 的首部希望声明一个新的变量,但是如果使用一个锁,你可能是想多个线程共享那个变量而不是新的变量。

posted @ 2022-05-06 19:38  r1-12king  阅读(123)  评论(0编辑  收藏  举报