当前位置: 首页 > news >正文

try-with-resources 工作原理

概述

try-with-resources 是 Java 7 引入的一种语法糖,用于简化资源管理,确保在使用资源后自动关闭它们。它是 try 语句的增强形式,可以在资源使用完毕后自动调用它们的 close() 方法,从而避免资源泄漏。

但这有个前提:就是资源类必须直接或间接实现了 java.lang.AutoCloseable ,详细信息请参阅资源定义板块。

基本语法

单个资源写法
try (ResourceType resource = new ResourceType()) {// 使用资源
} catch (ExceptionType e) {// 处理异常
}
多个资源写法
try (ResourceType resource1 = new ResourceType(); ResourceType resource2 = new ResourceType()) {// 使用资源
}

资源定义

任何实现了 java.lang.AutoCloseable 接口的类都可以作为 try-with-resources 语句的资源。AutoCloseable 接口只有一个方法:

public interface AutoCloseable {void close() throws Exception;
}

另一个常用的接口是 java.io.Closeable,它是 AutoCloseable 的子接口,专门用于 I/O 相关的资源,如 InputStreamReader

例如:Socket就实现了Closeableclose()方法

public synchronized void close() throws IOException {synchronized(closeLock) {if (isClosed())return;if (created)impl.close();closed = true;}
}

所以,用户也可以自定义类来实现AutoCloseable接口,实现close()方法后,即可在try-with-resources种使用。


CloseableAutoCloseable

  • AutoCloseable 是一个通用接口,可以被任何需要在使用后关闭的资源实现。
  • Closeable 继承自 AutoCloseable,并专门为 I/O 相关的资源设计。它的 close() 方法只能抛出 IOException,而 AutoCloseableclose() 方法可以抛出任何异常。

AutoCloseable 的设计更通用,而 Closeable 则专门用于处理 I/O 异常。

常见的实现了 Closeable 接口的 I/O 资源类

输入流和输出流读取和写入其他 I/O 类
java.io.InputStreamjava.io.Readerjava.io.RandomAccessFile
java.io.OutputStreamjava.io.Writerjava.nio.channels.FileChannel
java.io.FileInputStreamjava.io.FileReaderjava.util.zip.ZipFile
java.io.FileOutputStreamjava.io.FileWriter
java.io.BufferedInputStreamjava.io.BufferedReader
java.io.BufferedOutputStreamjava.io.BufferedWriter
java.io.DataInputStreamjava.io.PrintWriter
java.io.DataOutputStream

注:更多实现类信息请参考最后的补充信息板块

工作原理

资源声明和初始化

try 语句中声明的资源会被自动初始化,并且该初始化的资源是被自动关闭的。多个资源可以用分号分隔:

try (ResourceType resource1 = new ResourceType(); ResourceType resource2 = new ResourceType()) {// 使用资源
}
资源关闭顺序

多个资源按照它们声明的顺序关闭,即后声明的先关闭。例如,以上代码中的 resource2 会先于 resource1 被关闭。

自动关闭的实现

try 语句块执行完毕后(无论是否抛出异常),try-with-resources 语句会自动调用资源的 close() 方法。这个过程是通过编译器生成的字节码实现的,并不需要程序员显式编写关闭资源的代码。

例如,以下代码:

try (MyResource resource = new MyResource()) {// 使用资源
}

会被编译成类似于以下的字节码:

MyResource resource = null;
try {resource = new MyResource();// 使用资源
} catch (Exception e) {// 处理异常throw e;
} finally {if (resource != null) {try {resource.close();} catch (Exception e) {// 处理关闭资源时的异常}}
}

异常处理

try-with-resources 对异常处理也进行了改进。当 try 块中的代码和 close 方法都抛出异常时,close 方法抛出的异常将被抑制,真正的异常是 try 块中的异常。被抑制的异常可以通过 Throwable.getSuppressed() 方法获取。

例如:

try (MyResource resource = new MyResource()) {throw new Exception("Exception in try block");
} catch (Exception e) {// e 是 "Exception in try block"Throwable[] suppressed = e.getSuppressed();// suppressed[0] 是 close() 方法抛出的异常
}

总结

try-with-resources 提供了一种简洁、安全的资源管理方式,主要优点包括:

  • 简化资源管理:自动关闭资源,避免显式的 finally 代码块。
  • 减少代码冗余:不需要显式编写 close() 方法的调用。
  • 改进异常处理:更好地管理多个异常,避免遗漏资源关闭导致的资源泄漏。

这种语法糖极大地提高了代码的可读性和可靠性,是 Java 7 以来一个重要的语法改进。

补充

所有已知 Closeable 实现类

AbstractInterruptibleChannel, AbstractSelectableChannel, AbstractSelector, AsynchronousFileChannel, AsynchronousServerSocketChannel, AsynchronousSocketChannel, AudioInputStream, BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter, ByteArrayInputStream, ByteArrayOutputStream, CharArrayReader, CharArrayWriter, CheckedInputStream, CheckedOutputStream, CipherInputStream, CipherOutputStream, DatagramChannel, DatagramSocket, DataInputStream, DataOutputStream, DeflaterInputStream, DeflaterOutputStream, DigestInputStream, DigestOutputStream, FileCacheImageInputStream, FileCacheImageOutputStream, FileChannel, FileImageInputStream, FileImageOutputStream, FileInputStream, FileOutputStream, FileReader, FileSystem, FileWriter, FilterInputStream, FilterOutputStream, FilterReader, FilterWriter, Formatter, ForwardingJavaFileManager, GZIPInputStream, GZIPOutputStream, ImageInputStreamImpl, ImageOutputStreamImpl, InflaterInputStream, InflaterOutputStream, InputStream, InputStream, InputStream, InputStreamReader, JarFile, JarInputStream, JarOutputStream, LineNumberInputStream, LineNumberReader, LogStream, MemoryCacheImageInputStream, MemoryCacheImageOutputStream, MLet, MulticastSocket, ObjectInputStream, ObjectOutputStream, OutputStream, OutputStream, OutputStream, OutputStreamWriter, Pipe.SinkChannel, Pipe.SourceChannel, PipedInputStream, PipedOutputStream, PipedReader,PrintStream, PrintWriter, PrivateMLet, ProgressMonitorInputStream, PushbackInputStream, PushbackReader, RandomAccessFile, Reader, RMIConnectionImpl, RMIConnectionImpl_Stub, RMIConnector, RMIIIOPServerImpl, RMIJRMPServerImpl, RMIServerImpl, Scanner, SelectableChannel, Selector, SequenceInputStream, ServerSocketChannel, Socket, SocketChannel, SSLServerSocket, SSLSocket, StringBufferInputStream, StringReader, StringWriter, URLClassLoader, Writer, ZipFile, ZipInputStream, ZipOutputStream

所有已知 AutoCloseable 实现类

AbstractInterruptibleChannel, AbstractSelectableChannel, AbstractSelector, AsynchronousFileChannel, AsynchronousServerSocketChannel, AsynchronousSocketChannel, AudioInputStream, BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter, ByteArrayInputStream, ByteArrayOutputStream, CharArrayReader, CharArrayWriter, CheckedInputStream, CheckedOutputStream, CipherInputStream, CipherOutputStream, DatagramChannel, DatagramSocket, DataInputStream, DataOutputStream, DeflaterInputStream, DeflaterOutputStream, DigestInputStream, DigestOutputStream, FileCacheImageInputStream, FileCacheImageOutputStream, FileChannel, FileImageInputStream, FileImageOutputStream, FileInputStream, FileLock, FileOutputStream, FileReader, FileSystem, FileWriter, FilterInputStream, FilterOutputStream, FilterReader, FilterWriter, Formatter, ForwardingJavaFileManager, GZIPInputStream, GZIPOutputStream, ImageInputStreamImpl, ImageOutputStreamImpl, InflaterInputStream, InflaterOutputStream, InputStream, InputStream, InputStream, InputStreamReader, JarFile, JarInputStream, JarOutputStream, LineNumberInputStream, LineNumberReader, LogStream, MemoryCacheImageInputStream, MemoryCacheImageOutputStream, MLet, MulticastSocket, ObjectInputStream, ObjectOutputStream, OutputStream, OutputStream, OutputStream, OutputStreamWriter, Pipe.SinkChannel, Pipe.SourceChannel, PipedInputStream, PipedOutputStream, PipedReader、 PipedWriter, PrintStream, PrintWriter, PrivateMLet, ProgressMonitorInputStream, PushbackInputStream, PushbackReader, RandomAccessFile, Reader, RMIConnectionImpl, RMIConnectionImpl_Stub, RMIConnector, RMIIIOPServerImpl, RMIJRMPServerImpl, RMIServerImpl, Scanner, SelectableChannel, Selector, ServerSocket, ServerSocketChannel, Socket, SocketChannel, SSLServerSocket, SSLSocket, StringBufferInputStream, StringReader, StringWriter, URLClassLoader, Writer, XMLDecoder, XMLEncoder, ZipFile, ZipInputStream, ZipOutputStream

(注:补充信息来源自 Jdk1.8 API 文档)

相关文章:

  • DockerHub无法访问,国内镜像拉取迂回解决方案
  • 万字长文爆肝Spring(一)
  • CSS选择器种类总结
  • Spring Boot中Excel的导入导出的实现之EasyPoi框架使用教程
  • docker安装消息队列mq中的rabbit服务
  • python操作数据库,django操作数据库
  • 【Vue】自学笔记(四)
  • 有没有硅基生命?AGI在哪里?
  • 【面试干货】ArrayList、Vector、LinkedList的存储性能和特性比较
  • 类android设备reset过程
  • C++语法08 数据类型之间的强制转换
  • FlinkCDC 3.1.0 支持 Flink 1.18.0 版本选择
  • B树与B+树与Mysql innodb的B+树和其相关索引
  • 厂里资讯之总体架构介绍以及环境搭建
  • PostgreSQL基础(十四):PostgreSQL的数据迁移
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • C++11: atomic 头文件
  • overflow: hidden IE7无效
  • Python学习之路13-记分
  • Redis在Web项目中的应用与实践
  • Spring-boot 启动时碰到的错误
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • 官方解决所有 npm 全局安装权限问题
  • 前端技术周刊 2019-02-11 Serverless
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • 一个6年java程序员的工作感悟,写给还在迷茫的你
  • 用Canvas画一棵二叉树
  • 与 ConTeXt MkIV 官方文档的接驳
  • mysql 慢查询分析工具:pt-query-digest 在mac 上的安装使用 ...
  • #{}和${}的区别是什么 -- java面试
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (11)MSP430F5529 定时器B
  • (3)STL算法之搜索
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (第三期)书生大模型实战营——InternVL(冷笑话大师)部署微调实践
  • (二)延时任务篇——通过redis的key监听,实现延迟任务实战
  • (分布式缓存)Redis哨兵
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • (十六)视图变换 正交投影 透视投影
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • (一)Linux+Windows下安装ffmpeg
  • (中等) HDU 4370 0 or 1,建模+Dijkstra。
  • (转)socket Aio demo
  • (转)VC++中ondraw在什么时候调用的
  • *算法训练(leetcode)第四十五天 | 101. 孤岛的总面积、102. 沉没孤岛、103. 水流问题、104. 建造最大岛屿
  • ./configure、make、make install 命令
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .netcore如何运行环境安装到Linux服务器
  • .Net的DataSet直接与SQL2005交互
  • .net连接MySQL的方法
  • @LoadBalanced 和 @RefreshScope 同时使用,负载均衡失效分析
  • @NestedConfigurationProperty 注解用法
  • @PreAuthorize注解