能直接用 try-with-resources 的类必须显式实现 AutoCloseable 接口,如 FileInputStream、BufferedReader、Connection 等;Scanner、老版 JDBC 驱动类及未实现该接口的自定义类则不可用。

哪些类能直接用 try-with-resources?看它有没有实现 AutoCloseable
不是“有 close() 方法就能用”,而是必须显式实现 AutoCloseable 接口——这是编译器硬性检查的门槛。JDK 中绝大多数标准资源类都已满足,比如:
-
FileInputStream、BufferedReader、ObjectOutputStream -
java.sql.Connection(JDBC 4.0+ 驱动)、PreparedStatement、ResultSet -
Socket、ServerSocket、FileChannel
但要注意几个典型反例:
-
Scanner虽然有close(),但关它可能顺带关掉System.in,慎用 - 老版本 JDBC 驱动里的
Connection可能没实现该接口,得查 Javadoc 或源码确认 - 自己封装的工具类,哪怕写了
public void close() { ... },没加implements AutoCloseable就会编译报错:cannot be auto-closed; it does not implement AutoCloseable
自定义资源怎么接入 try-with-resources?只需两步
你写的类只要满足两个条件,就能被 try 括号安全接纳:
- 声明
implements AutoCloseable(不用管Closeable,它是子接口,兼容) - 重写
close()方法,把释放逻辑(如关闭底层流、释放锁、注销监听)放进去
示例:
立即学习“Java免费学习笔记(深入)”;
public class DatabaseSession implements AutoCloseable {
private final Connection conn;
public DatabaseSession(Connection conn) {
this.conn = conn;
}
@Override
public void close() throws SQLException {
if (conn != null && !conn.isClosed()) {
conn.close(); // 真正清理动作
}
}
}
之后就能这么写:
try (DatabaseSession session = new DatabaseSession(conn)) {
// 执行查询
}
多个资源一起用时,关闭顺序为什么重要?
资源按声明**从左到右初始化**,但关闭是**从右到左逆序执行**——这个顺序不是约定,而是资源依赖关系的强制保障。
比如数据库操作:
try (Connection conn = ds.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery()) {
// 处理结果
}
实际关闭顺序是:rs.close() → stmt.close() → conn.close()。如果反过来写成 ResultSet 在前、Connection 在后,rs.close() 可能因连接已断而抛异常,或直接静默失败。
嵌套流也一样:BufferedReader 必须在 FileReader 之前声明,否则底层流先关,上层流再读/关就出问题。
什么情况下别硬套 try-with-resources?
它不是万能语法糖,强行套用反而埋坑:
-
资源由外部传入且生命周期不归你管:比如方法参数是
InputStream,你关了它,调用方后续再用就IOException了 -
close() 有副作用且不能提前触发:例如某些缓存类的
close()会清空全部数据,你希望它在程序退出时才执行 -
需要在关闭后继续访问资源状态:比如关流后还要检查
isClosed(),那得手动控制时机 - 资源初始化失败后,你仍需对已创建的部分做特殊处理:try-with-resources 会自动关已成功构造的资源,但不会给你干预机会
最容易被忽略的一点:即使 close() 抛异常,它也会被抑制(suppressed),默认不打印。如果业务上必须感知关闭失败(比如写日志、发告警),就得主动调用 e.getSuppressed() 检查——这点连很多日志框架都不默认支持,得自己兜底。










