try-with-resources使用详解

本文最后更新于:2025年2月18日 下午

概述

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

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

基本语法

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

资源定义

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

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

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

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

1
2
3
4
5
6
7
8
9
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.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
2
3
4
try (ResourceType resource1 = new ResourceType(); 
ResourceType resource2 = new ResourceType()) {
// 使用资源
}

资源关闭顺序

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

自动关闭的实现

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

例如,以下代码:

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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() 方法获取。

例如:

1
2
3
4
5
6
7
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 文档)


try-with-resources使用详解
https://superlovelace.top/2024/06/12/Try-with-resource用法详解/
作者
棱境
发布于
2024年6月12日
更新于
2025年2月18日
许可协议