目录

一、资源关闭背景

二、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接口,

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

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

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

3.2 实现原理

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

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

3.3 异常抑制

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

var2.addSuppressed(var11);

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

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

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

public static void writeToFileZipFileContents(String zipFileName,String outputFileName)throws java.io.IOException {java.nio.charset.Charset charset =java.nio.charset.StandardCharsets.US_ASCII;java.nio.file.Path outputFilePath =java.nio.file.Paths.get(outputFileName);// Open zip file and create output file with // try-with-resources statementtry (java.util.zip.ZipFile zf =new java.util.zip.ZipFile(zipFileName);java.io.BufferedWriter writer = java.nio.file.Files.newBufferedWriter(outputFilePath, charset)) {// Enumerate each entryfor (java.util.Enumeration entries =zf.entries(); entries.hasMoreElements();) {// Get the entry name and write it to the output fileString newLine = System.getProperty("line.separator");String zipEntryName =((java.util.zip.ZipEntry)entries.nextElement()).getName() +newLine;writer.write(zipEntryName, 0, zipEntryName.length());}}
}

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语句包含以分号分隔的两个声明ZipFileBufferedWriter

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

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

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

public static void viewTable(Connection con) throws SQLException {String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES";try (Statement stmt = con.createStatement()) {ResultSet rs = stmt.executeQuery(query);while (rs.next()) {String coffeeName = rs.getString("COF_NAME");int supplierID = rs.getInt("SUP_ID");float price = rs.getFloat("PRICE");int sales = rs.getInt("SALES");int total = rs.getInt("TOTAL");System.out.println(coffeeName + ", " + supplierID + ", " + price + ", " + sales + ", " + total);}} catch (SQLException e) {JDBCTutorialUtilities.printSQLException(e);}
}

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

注意

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

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

四、文件读取工具类

import java.io.*;/*** @Title: 文件读取* @ClassName: com.ruoyi.vr.util.FileUtils.java* @Description:** @Copyright 2020-2021 - Powered By 研发中心* @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-with-resource:自动地关闭资源相关推荐

  1. 哈哈,咱们团队早就不用try-catch-finally关闭资源了!

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 代码一定得写的优雅一点! 你还在使用try-catch-final ...

  2. 你还在使用 try-catch-finally 关闭资源?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:何甜甜在吗 链接:https://juejin.im/pos ...

  3. 你还在使用 try-catch-finally 关闭资源?不太优雅~

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:硬刚一周,3W字总结,一年的经验告诉你如何准备校招! 个人原创100W+访问量博客:点击前往,查看更多 作者:何 ...

  4. Resource接口,及资源

    Resource介绍 编码的时候,除了代码本身,我们还需要对外部的资源进行处理.例如:URL资源.URI资源.File资源.ClassPath相关资源.服务器相关资源(VFS等)等等. 而这些资源的处 ...

  5. Java如何实现文件拷贝操作和如何正确关闭资源

    使用字节流完成文件的拷贝: 使用字节输入流(FileInputStream)将源文件中的数据读进来,同时使用字节输出流(FileOutputStream)将读进来的数据写到目标文件中,即一边读一边写, ...

  6. 【愚公系列】2021年12月 网络工程-window10自动更新关闭

    文章目录 一.window10自动更新关闭 二.使用步骤 1.服务启动项关闭 2.关闭组策略选项 总结 一.window10自动更新关闭 window10自动更新可能产生以下问题 突然更新.尤其是在关 ...

  7. Effective java 系列之更优雅的关闭资源-try-with-resources

    背景: 在Java编程过程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们.因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,如果我们不在 ...

  8. 优雅地关闭资源,try-with-resource语法和lombok@Cleanup

    资源的打开就需要对应的关闭,但我们常会忘记关闭资源,或在多处代码关闭资源感到杂乱,有没有简洁的关闭方法呢? 自动关闭资源类需实现AutoCloseable接口和配合try-with-resource语 ...

  9. 为DbHelper工具类添加关闭资源的方法 jdbc 20210412_212728.mp4

    为DbHelper工具类添加关闭资源的方法 jdbc 给dbhelper工具类添加关闭资源的方法 接收所有的资源对象 然后关闭他们 代码 import java.sql.*;public class ...

最新文章

  1. 简单理解js闭包、类型引用....第一章
  2. 以下属于单例模式的优点的是_三、单例模式详解
  3. SpringBoot整合Minio 项目中使用自己文件存储服务器
  4. 第五章 编写主引导扇区代码
  5. 前端面试之前要准备的那些事
  6. windows 播放MP3音乐
  7. macOS上,实现Wireshark手机抓包
  8. 20172310《程序设计与数据结构》(下)实验二:二叉树实验报告
  9. 【LeetCode】【HOT】98. 验证二叉搜索树(递归)
  10. mysql+web日志分析工具_用Python+MySQL实现2017年web日志分析报告
  11. 对文件夹添加共享属性!
  12. Java网络编程学习汇总
  13. 富士康计算机主板官网,富士康主板官网?富士康主板刷bios工具?foxconn主板官网?富士康主板怎么样...
  14. JAX-RS之Jersey入门
  15. 多测师杭州拱墅校区__肖sir__软件测试生命周期(4)
  16. python使用requests模块下载文件
  17. Oracle AutoVue 使用范围
  18. 如何避免拼多多售后?拼多多售后有哪些规则?
  19. 浅析U.2接口NVMe SSD双端口模式(上)——应用模式与设计实现
  20. 新上线的“闪电”算法

热门文章

  1. JDK之ZGC介绍.JAVAEE最新JDK剖析
  2. 武汉理工计算机与名校的差距
  3. 《操作系统》第一章 知识点整理
  4. 2020考研初试经验贴
  5. 工作3年的Java程序员如何成功跳槽,7K一飞到22K
  6. E420笔记本升级固态硬盘
  7. 机器视觉实验四: 为人脸添加装饰物特效实验(OpenCV-python代码)
  8. 简要讨论python对于1688的关键字搜索、商品详情在电商运营大数据分析、电商选品、竞品分析上的帮助
  9. ybt1003:对齐输出
  10. 039-070前端学习