try-with-resources使用详解
本文最后更新于:2025年2月18日 下午
概述
try-with-resources
是 Java 7 引入的一种语法糖,用于简化资源管理,确保在使用资源后自动关闭它们。它是 try
语句的增强形式,可以在资源使用完毕后自动调用它们的 close()
方法,从而避免资源泄漏。
但这有个前提:就是资源类必须直接或间接实现了
java.lang.AutoCloseable
,详细信息请参阅资源定义板块。
基本语法
单个资源写法
1 |
|
多个资源写法
1 |
|
资源定义
任何实现了 java.lang.AutoCloseable
接口的类都可以作为 try-with-resources
语句的资源。AutoCloseable
接口只有一个方法:
1 |
|
另一个常用的接口是 java.io.Closeable
,它是 AutoCloseable
的子接口,专门用于 I/O 相关的资源,如 InputStream
和 Reader
。
例如:Socket
就实现了Closeable
的close()
方法
1 |
|
所以,用户也可以自定义类来实现AutoCloseable
接口,实现close()
方法后,即可在try-with-resources
种使用。
Closeable
和 AutoCloseable
AutoCloseable
是一个通用接口,可以被任何需要在使用后关闭的资源实现。Closeable
继承自AutoCloseable
,并专门为 I/O 相关的资源设计。它的close()
方法只能抛出IOException
,而AutoCloseable
的close()
方法可以抛出任何异常。
AutoCloseable
的设计更通用,而 Closeable
则专门用于处理 I/O 异常。
常见的实现了 Closeable
接口的 I/O 资源类
输入流和输出流 | 读取和写入 | 其他 I/O 类 |
---|---|---|
java.io.InputStream |
java.io.Reader |
java.io.RandomAccessFile |
java.io.OutputStream |
java.io.Writer |
java.nio.channels.FileChannel |
java.io.FileInputStream |
java.io.FileReader |
java.util.zip.ZipFile |
java.io.FileOutputStream |
java.io.FileWriter |
|
java.io.BufferedInputStream |
java.io.BufferedReader |
|
java.io.BufferedOutputStream |
java.io.BufferedWriter |
|
java.io.DataInputStream |
java.io.PrintWriter |
|
java.io.DataOutputStream |
注:更多实现类信息请参考最后的补充信息板块
工作原理
资源声明和初始化
在 try
语句中声明的资源会被自动初始化,并且该初始化的资源是被自动关闭的。多个资源可以用分号分隔:
1 |
|
资源关闭顺序
多个资源按照它们声明的顺序关闭,即后声明的先关闭。例如,以上代码中的 resource2
会先于 resource1
被关闭。
自动关闭的实现
在 try
语句块执行完毕后(无论是否抛出异常),try-with-resources
语句会自动调用资源的 close()
方法。这个过程是通过编译器生成的字节码实现的,并不需要程序员显式编写关闭资源的代码。
例如,以下代码:
1 |
|
会被编译成类似于以下的字节码:
1 |
|
异常处理
try-with-resources
对异常处理也进行了改进。当 try
块中的代码和 close
方法都抛出异常时,close
方法抛出的异常将被抑制,真正的异常是 try
块中的异常。被抑制的异常可以通过 Throwable.getSuppressed()
方法获取。
例如:
1 |
|
总结
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
文档)