在此之前,我一直使用`try-catch-finally`的`catch`或`finally`语句块关闭资源,比如输入流、输出流、读写流等。
比如下面的例子:当读入流或写出流出现异常时,我们需要在`catch`语句块中对其执行资源关闭操作。而读写流的`close`方法本身就会抛出`IOException`,也需要处理异常。
```java
/**
* @author: miantiao
* @date: 2021/9/14
*/
public class TryCatch {
public static void main(String[] args) {
String path = "F:\\test.txt";
String newPath = "F:\\new.txt";
BufferedReader bufferedReader = null;
BufferedWriter bufferedWriter = null;
File readFile = new File(path);
File writeFile = new File(newPath);
try {
bufferedReader = new BufferedReader(new FileReader(readFile));
bufferedWriter = new BufferedWriter(new FileWriter(writeFile));
String s = "";
while ((s = bufferedReader.readLine()) != null) {
bufferedWriter.write(s);
}
bufferedWriter.flush();
} catch (Exception e) {
//关闭读入流
try {
bufferedReader.close();
} catch (IOException e1) {
e1.printStackTrace();
}
//关闭写出流
try {
bufferedWriter.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
```
在这种情况下如果只涉及一种资源的关闭还好说,但有多个资源时就会出现一种奇观,那就是在执行第一种资源的关闭操作时出现异常,那么剩余的资源都没有办法正常关闭。
然而JDK在1.7版本中就提供了一种优雅的关闭资源的方式`try-with-resources`(不是今天遇到问题,我都发现不了,真的菜的真实~~)
> The try-with-resources statement is a try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try-with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements java.lang.AutoCloseable, which includes all objects which implement java.io.Closeable, can be used as a resource.
上面是Oracle官方给出的对`try-with-resources`的解释:`try-with-resources`语句是一种声明一个或多个资源的`try`语句。 资源是程序完成后必须关闭的对象。`try-with-resources`语句确保每个资源在语句结束时关闭。 任何实现`java.lang.AutoCloseable`的对象,包括实现`java.io.Closeable`的所有对象,都可以用作资源。
这真的太友好了,再也不需要我用我这小脑瓜子想如何关闭资源了。以上面的代码为例,可以用`try-with-resources`改造如下:
```java
/**
* @author: miantiao
* @date: 2021/9/14
*/
public class TryWithResource {
public static void main(String[] args) {
String path = "F:\\test.txt";
String newPath = "F:\\new.txt";
File readFile = new File(path);
File writeFile = new File(newPath);
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(readFile));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(writeFile))) {
String s = "";
while ((s = bufferedReader.readLine()) != null) {
bufferedWriter.write(s);
}
bufferedWriter.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
```
但是值得注意的是只有实现了`java.lang.AutoCloseable`接口或实现了`java.io.Closeable`接口的对象,才可以使用`try-with-catch`语法来关闭资源。其中,Closeable接口是继承自AutoCloseable接口的。
```java
/**
* A {@code Closeable} is a source or destination of data that can be closed.
* The close method is invoked to release resources that the object is
* holding (such as open files).
*
* @since 1.5
*/
public interface Closeable extends AutoCloseable {}
```
上述例子中,`BufferedReader`和`BufferedWriter`都间接实现了Closeable接口。
```java
//BufferedReader 的继承关系
public class BufferedReader extends Reader
public abstract class Reader implements Readable, Closeable
//BufferedWriter 的继承关系
public class BufferedWriter extends Writer
public abstract class Writer implements Appendable, Closeable, Flushable
```
Reference: [The try-with-resources Statement](https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html)
![在Java中如何优雅地关闭资源](https://miantiao.online/upload/2021/01/wallhaven-0pzwzj-fe1539a2925d40cb935292ed913138e5.jpg)
在Java中如何优雅地关闭资源