背景:

在Java编程过程中,如果打开了外部资源(文件、数据库连接、网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们。因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,如果我们不在编程时确保在正确的时机关闭外部资源,就会导致外部资源泄露,紧接着就会出现文件被异常占用,数据库连接过多导致连接池溢出等诸多很严重的问题。

传统关闭资源方式(一般JDK版本低于1.7)

/**
* 根据路径创建文件,如果路径文件夹不存在,就创建
* @param filePath
* @return
*/
public static File createFileAbsolute(String filePath) throws IOException {
File file = new File(filePath);
File fileParent = file.getParentFile(); if(!fileParent.exists()){
fileParent.mkdirs();
}
file.createNewFile();
return file;
} /**
* 传统写法,JDK1.6
* @param dataStr
* @return
*/
public static long write2FileTradition(String dataStr,String filePath){
long fileSize = 0L;
RandomAccessFile raf = null;
FileChannel fchannel = null;
try {
raf = new RandomAccessFile(createFileAbsolute(filePath),"rw");
fchannel = raf.getChannel(); ByteBuffer buf = ByteBuffer.allocate(); buf.clear();
buf.put(dataStr.getBytes());
buf.flip(); while(buf.hasRemaining()){
fchannel.write(buf);
} fileSize = fchannel.size(); } catch (FileNotFoundException e) {
logger.error("file not found",e);
} catch (IOException e) {
logger.error("IO exception",e);
}finally{
      
IOUtils.close(fchannel);
IOUtils.close(raf);
}
return fileSize;
}

注意:如果是节点流和处理流,可直接关闭处理流,因为io流使用了装饰模式,所以关闭处理流时,会调用节点流的close()方法。

JDK1.7以后关闭资源的方式

try-with-resource语法(语法糖)

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

那什么是try-with-resource呢?简而言之,当一个外部资源的句柄对象(比如FileInputStream对象)实现了AutoCloseable接口,那么就可以将上面的板式代码简化为如下形式:

/**
* JDK1.7 关闭资源语法糖
*
* @param dataStr
* @param filePath
* @return
*/
public static long write2File(String dataStr, String filePath) {
long fileSize = 0L;
try (
RandomAccessFile raf = new RandomAccessFile(createFileAbsolute(filePath), "rw");
FileChannel fchannel = raf.getChannel()
) {
ByteBuffer buf = ByteBuffer.allocate(1024); buf.clear();
buf.put(dataStr.getBytes());
buf.flip(); while (buf.hasRemaining()) {
fchannel.write(buf);
} fileSize = fchannel.size(); } catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} return fileSize;
}

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

反编译后源码:

  public static long write2File(String dataStr, String filePath) {
long fileSize = 0L; try {
RandomAccessFile raf = new RandomAccessFile(filePath, "rw");
Throwable var5 = null; try {
FileChannel fchannel = raf.getChannel();
Throwable var7 = null; try {
ByteBuffer buf = ByteBuffer.allocate(1024);
buf.clear();
buf.put(dataStr.getBytes());
buf.flip(); while(buf.hasRemaining()) {
fchannel.write(buf);
} fileSize = fchannel.size();
} catch (Throwable var34) {
var7 = var34;
throw var34;
} finally {
if (fchannel != null) {
if (var7 != null) {
try {
fchannel.close();
} catch (Throwable var33) {
var7.addSuppressed(var33);
}
} else {
fchannel.close();
}
} }
} catch (Throwable var36) {
var5 = var36;
throw var36;
} finally {
if (raf != null) {
if (var5 != null) {
try {
raf.close();
} catch (Throwable var32) {
var5.addSuppressed(var32);
}
} else {
raf.close();
}
} }
} catch (FileNotFoundException var38) {
logger.error("file not found", var38);
} catch (IOException var39) {
logger.error("IO exception", var39);
} return fileSize;
}

异常抑制

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

var2.addSuppressed(var11);

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

这里理解一点,就是try块中抛出的异常,在finally也抛出异常时,就会丢失,所以通常在finally不抛异常,而是通过 addSuppressed()方法将异常抑制住。

总结:

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

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

参考:

https://www.cnblogs.com/itZhy/p/7636615.html

https://www.cnblogs.com/langtianya/p/5139465.html

Effective java 系列之更优雅的关闭资源-try-with-resources的更多相关文章

  1. Java进阶知识点:更优雅地关闭资源 - try-with-resource

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

  2. Java进阶知识点3:更优雅地关闭资源 - try-with-resource及其异常抑制

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

  3. 更优雅地关闭资源 - try-with-resource及其异常抑制

    原文:https://www.cnblogs.com/itZhy/p/7636615.html 一.背景 我们知道,在Java编程过程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必须在 ...

  4. 更优雅地关闭资源 - try-with-resource及其异常抑制--转载

    原文地址:https://www.cnblogs.com/itZhy/p/7636615.html 一.背景 我们知道,在Java编程过程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必 ...

  5. 更优雅地关闭资源 - try-with-resource

    https://www.cnblogs.com/hihtml5/p/6505317.html

  6. Effective Java —— 优先考虑依赖注入来引用资源

    本文参考 本篇文章参考自<Effective Java>第三版第五条"Prefer dependency injection to hardwiring resources&qu ...

  7. JDK-7新特性,更优雅的关闭流-java try-with-resource语句使用

    前言 公司最近代码质量整改,需要对大方法进行调整,降低到50行以下,对方法的深度进行降低,然后有些文件涉及到流操作,很多try/catch/finally语句,导致行数超出规范值,使用这个语法可以很好 ...

  8. Effective java 系列之避免过度同步和不要使用原生态类型,优先考虑泛型

    避免过度同步(67):在一个被同步的方法或代码块中,不要调用哪些被设计成被覆盖的方法或者是由客户端以函数对象的形式提供的方法(21). 有点拗口,书上提供的创建者与观察者模式,add方法太多,看得眼花 ...

  9. Java中如何更优雅的处理空值

    经常看到项目中存在到处空值判断的情况,这些判断,会让人觉得摸不着头绪,它的出现很有可能和当前的业务逻辑并没有关系.但它会让你很头疼.有时候,更可怕的是系统因为这些空值的情况,会抛出空指针异常,导致业务 ...

随机推荐

  1. 用微信小程序连接leancloud数据库注意事项~

    具体步骤转载如下: 官网教程 大佬提示 注意事项: 1.下载的av-weapp-min.js,需要放在当前项目名称的子目录pages下 2.如上述教程,需要注册leancloud和AppID,并写在a ...

  2. Jmeter GIS调用-->参数化+正则表达式提取器+后置处理器+逻辑控制器

    一.参数化: 1.添加线程组 2.添加HTTP请求 3.CSV 数据文件设置 HTTP请求参数话 4.正则表达式提取器 5.逻辑控制器 可以or    and 等 6.后置处理器写入文件 FileWr ...

  3. sql 查询所有作业的详情

    DECLARE @WeekDays TABLE ( freq_interval INT, weekdays ) ) INSERT INTO @WeekDays ,N'星期日 ' UNION ALL , ...

  4. JavaScript自定义事件和触发(createEvent, dispatchEvent)

    $(dom).addEvent("ft", function() { alert("走起"); }); // 创建 var evt = document.cre ...

  5. 2018-2019-2 《网络对抗技术》Exp0 Kali安装 Week1 20165215

    2018-2019-2 <网络对抗技术>Exp0 Kali安装 Week1 20165215 目录 Kali的下载及安装 网络配置 设置共享文件夹及剪切板 更新软件源 [Kali的下载及安 ...

  6. Django数据查询方法总结

      __exact 精确等于 like ‘aaa’__iexact 精确等于 忽略大小写 ilike ‘aaa’__contains 包含 like ‘%aaa%’__icontains 包含 忽略大 ...

  7. js 手动插入meta标签和script标签

    // 插入 meta 标签 var oMeta = document.createElement('meta'); oMeta.content = 'width=device-width, initi ...

  8. ActiveMQ下载与安装(Linux环境下进行)

    下载 官方网站:http:activemq.apache.org/ 安装(liunx) 1.将apache-activemq-5.12.0-bin.tar.gz(liunx环境下的压缩包)上传至服务器 ...

  9. 解决ping不通win7主机

    之前在路由器上ping笔记本发现ping不通,但是笔记本ping路由器通,也没多想.今天想起来可能是win7的防火墙作怪,以前上课虚拟机好像也是ping不通宿主机,但是宿主机能ping通虚拟机. 简单 ...

  10. [Python]数据挖掘(1)、梯度下降求解逻辑回归——考核成绩分类

    ps:本博客内容根据唐宇迪的的机器学习经典算法  学习视频复制总结而来 http://www.abcplus.com.cn/course/83/tasks 逻辑回归 问题描述:我们将建立一个逻辑回归模 ...