目录

一、资源关闭背景

二、JDK7之前的资源关闭方式

三、JDK7及其之后的资源关闭方式

3.1 try-with-resource语法

3.2 实现原理

3.3 异常抑制

3.4 try-with-resources语句中声明一个或多个资源

四、文件读取工具类

五、总结



一、资源关闭背景

我们知道,在Java编程过程中,如果 打开了外部资源(文件、数据库连接、网络连接等) ,我们必须在这些外部资源使用完毕后,手动关闭它们。

因为外部资源不由 JVM 管理,无法享用JVM的垃圾回收机制,如果我们 不在编程时确保在正确的时机关闭外部资源 就会导致外部资源泄露 紧接着就会出现文件被异常占用,数据库连接过多导致连接池溢出 等诸多很严重的问题。


二、JDK7之前的资源关闭方式

为了确保外部资源一定要被关闭,通常关闭代码被写入finally代码块中,当然我们还必须注意到关闭资源时可能抛出的异常,于是变有了下面的经典代码:

public static void main(String[] args) {
    FileInputStream inputStream = null;
    try {
        inputStream = new FileInputStream(new File("test"));
        System.out.println(inputStream.read());
    } catch (IOException e) {
        throw new RuntimeException(e.getMessage(), e);
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage(), e);
}


熟悉其他语言的朋友可能会开始吐槽了,在C++中,我们可以把关闭资源的代码放在析构函数中, 在C#中,我们有using代码块 。这些语法都有一个共同的特性, 让外部资源的关闭行为与外部资源的句柄对象的生命周期关联,当外部资源的句柄对象生命周期终结时(例如句柄对象已出作用域),外部资源的关闭行为将被自动调用 。这样不仅更加符合面向对象的编程理念(将关闭外部资源的行为内聚在外部资源的句柄对象中),也让代码更加简洁易懂。怎么到了Java这里,就找不到自动关闭外部资源的语法特性了呢。


三、JDK7及其之后的资源关闭方式

3.1 try-with-resource语法

确实,在JDK7以前,Java没有自动关闭外部资源的语法特性,直到JDK7中新增了try-with-resource语法,才实现了这一功能。

那什么是try-with-resource呢?

简而言之, 当一个外部资源的句柄对象(比如FileInputStream对象)实现了AutoCloseable接口,

那么就可以将上面的板式代码简化为如下形式:

将外部资源的句柄对象的创建放在try关键字后面的括号中 ,当这个try-catch代码块执行完毕后,Java会确保外部资源的close方法被调用。代码是不是瞬间简洁许多!


3.2 实现原理

try-with-resource并不是JVM虚拟机的新增功能,只是JDK实现了一个语法糖,当你将上面代码反编译后会发现,其实对JVM虚拟机而言,它看到的依然是之前的写法:

3.3 异常抑制

通过反编译的代码,大家可能注意到代码中有一处对异常的特殊处理:

这是try-with-resource语法涉及的另外一个知识点,叫做异常抑制。当对外部资源进行处理(例如读或写)时,如果遭遇了异常,且在随后的关闭外部资源过程中,又遭遇了异常,那么你catch到的将会是对外部资源进行处理时遭遇的异常,关闭资源时遭遇的异常将被“抑制”但不是丢弃,通过异常的getSuppressed方法,可以提取出被抑制的异常。


3.4 try -with-resources语句中声明一个或多个资源

您可以在 try -with-resources语句中声明一个或多个资源。以下示例检索zip文件中打包的文件的名称, zipFileName 并创建包含这些文件名称的文本文件:

In this example, the try -with-resources statement contains two declarations that are separated by a semicolon: ZipFile and BufferedWriter . When the block of code that directly follows it terminates, either normally or because of an exception, the close methods of the BufferedWriter and ZipFile objects are automatically called in this order. Note that the close methods of resources are called in the opposite order of their creation.

在此示例中, try -with-resources语句包含以分号分隔的两个声明 ZipFile BufferedWriter

当直接跟随它的代码块正常或由于异常而终止时,将按 BufferedWriter ZipFile 对象的 close 方法 顺序自动调用

请注意,资源的关闭方法按其创建的 相反 顺序调用。

以下示例使用 try -with-resources语句自动关闭 java.sql.Statement 对象:

java.sql.Statement 此示例中使用的资源是JDBC 4.1及更高版本API的一部分。

注意

A try -with-resources语句可以像普通 try 语句一样拥有 catch finally语块

try -with-resources语句中,任何 catch finally 块在声明的资源关闭后运行。


四、文件读取工具类

import java.io.*;
 * @Title: 文件读取
 * @ClassName: com.ruoyi.vr.util.FileUtils.java
 * @Description:
 * @author: 王延飞
 * @date: 2020/1/24 17:28
 * @version V1.0
public class FileUtils {
     * 将文本文件中的内容读入到String中
     * @param buffer buffer
     * @param filePath 文件路径
     * @throws IOException 异常
     * @date 2020-1-7





    
    public static String readToBuffer(StringBuffer buffer, String filePath) throws IOException {
        InputStream is = new FileInputStream(filePath);
        String line; // 用来保存每行读取的内容
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        line = reader.readLine(); // 读取第一行
        while (line != null) { // 如果 line 为空说明读完了
            buffer.append(line); // 将读到的内容添加到 buffer 中
            buffer.append("\n"); // 添加换行符
            line = reader.readLine(); // 读取下一行
        reader.close();
        is.close();
        return buffer.toString();
     * @Title: 将文本文件中的内容读入到String中 <JDK8自动地关闭资源>
     * @MethodName: readToBufferJDK8
     * @param buffer
     * @param filePath
     * @Return void
     * @Exception
     * @Description: https://blog.csdn.net/fly910905/article/details/86093723
     * @author: 王延飞
     * @date: 2020/10/24 17:40
    public static String readToBufferJDK8(StringBuffer buffer, String filePath) throws IOException {
        String line; // 用来保存每行读取的内容
        File file = new File(filePath);
        if (file.exists()) {
            try (InputStream is = new FileInputStream(filePath);
                 BufferedReader reader = new BufferedReader(new InputStreamReader(is));
                while ((line = reader.readLine()) != null) { // 读取行,如果 line 为空说明读完了
                    buffer.append(line); // 将读到的内容添加到 buffer 中
            } catch (IOException e) {
                return null;
        return buffer.toString();
    public static void main(String[] args) throws IOException {
        StringBuffer sb = new StringBuffer();
        String s = FileUtils.readToBufferJDK8(sb, "C:\\Users\\FLY\\Desktop\\线下实训\\test.html");
        System.out.println(s);
}


五、总结

1、当一个外部资源的句柄对象实现了AutoCloseable接口,JDK7中便可以利用try-with-resource语法更优雅的关闭资源,消除板式代码。

2、try-with-resource时,如果对外部资源的处理和对外部资源的关闭均遭遇了异常,“关闭异常”将被抑制,“处理异常”将被抛出,但“关闭异常”并没有丢失,而是存放在“处理异常”的被抑制的异常列表中。

参考链接: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html



还在用try-finally中关闭各种资源,你不累吗?
相信大多数人在使用Java的时候,经常会使用到try-finally去关闭各种打开的资源,比如数据库连接,文件流等。于是,我们的代码经常就会像这个样子:
【Android 安装包优化】移除无用资源 ( 自动移除无用资源 | 直接引用资源 | 动态获取资源 id | Lint 检查资源 )(二)
【Android 安装包优化】移除无用资源 ( 自动移除无用资源 | 直接引用资源 | 动态获取资源 id | Lint 检查资源 )(二)
【Android 安装包优化】移除无用资源 ( 自动移除无用资源 | 直接引用资源 | 动态获取资源 id | Lint 检查资源 )(一)
【Android 安装包优化】移除无用资源 ( 自动移除无用资源 | 直接引用资源 | 动态获取资源 id | Lint 检查资源 )(一)