资源泄露问题

try-with-resource 是 Java 7 引入的一个特性,用于简化资源管理。在处理像文件、网络连接、数据库连接这类需要手动关闭的资源时,传统的 try-catch-finally 结构可能会让代码变得复杂,而且容易因为忘记关闭资源而导致资源泄漏。try-with-resource 可以自动关闭实现了 AutoCloseable 接口的资源,让代码更简洁、安全。

某次手动强制停止下面问题代码任务,再重新触发后,出现连接泄露报错,查资料后发现,存在的问题有:1.在请求失败和抛出异常的情况下连接资源都不能正确关闭

问题代码:

ini 复制代码
try {  
OkHttpClient client = new OkHttpClient()  
.newBuilder()  
.connectTimeout(30 * 1000, TimeUnit.MILLISECONDS)  
.readTimeout(30 * 1000, TimeUnit.MILLISECONDS)  
.authenticator((route, response) -> {  
String credential = xxxx;  
return response.request().newBuilder().header("Authorization", credential).build();  
}).build();  
  
String requestUrl = xxxxxxxxxxx;  
Request request = new Request.Builder()  
.url(requestUrl)  
.build();  
  
Response response = client.newCall(request).execute();  
if (response.isSuccessful()) {  
String res = response.body().string();  
return res;  
} else {  
logger.error("请求失败,状态码: {}", response.code());  
return null;  
}  
  
} catch (IOException e) {  
logger.error("捕获异常");  
return null;  
}

解决:使用try-with-resource自动关闭资源,修改后:

ini 复制代码
OkHttpClient client = new OkHttpClient()  
.newBuilder()  
.connectTimeout(30 * 1000, TimeUnit.MILLISECONDS)  
.readTimeout(30 * 1000, TimeUnit.MILLISECONDS)  
.authenticator((route, response) -> {  
String credential = xxxx;  
return response.request().newBuilder().header("Authorization", credential).build();  
}).build();  
  
String requestUrl = xxxxxxxxxxxxxxxxxxx;  
Request request = new Request.Builder()  
.url(requestUrl)  
.build();  
  
try (Response response = client.newCall(request).execute()) {  
ResponseBody body = response.body();  
if (body == null) {  
logger.error("响应体为空");  
return null;  
}  
  
if (response.isSuccessful()) {  
String res = body.string();   
return res;  
} else {  
logger.error("请求失败,状态码: {}", response.code());  
return null;  
}  
} catch (IOException e) {  
logger.error("捕获异常");  
return null;  
}

!!!请我以后习惯性使用try with resources

什么时候使用try with resources

可以用 try with resources关闭的条件是什么

一个对象要能够被 try-with-resources 语句管理(即可以放在 try (...) 的括号中),必须满足一个核心条件 :该对象的类必须直接或间接实现 java.lang.AutoCloseable 接口。(上面的Response类是实现了Closeable类,而Closeable实现了AutoCloseable)

  • AutoCloseable 接口

    • 这是 Java 7 引入的接口,是 try-with-resources 语句的基础 , 任何实现了 AutoCloseable 的类,都可以被 try-with-resources 管理。

    • 它只定义了一个方法:

    csharp 复制代码
    public void close() throws Exception;
  • Closeable 接口

    • java.io.CloseableAutoCloseable子接口

    • 它重写了 close() 方法,抛出更具体的 IOException

    csharp 复制代码
    public void close() throws IOException;
  • 结论 :所有实现了 Closeable 的类,也自动实现了 AutoCloseable,因此也支持 try-with-resources所以,只要一个类实现了 AutoCloseableCloseable,就可以用 try-with-resources

常见支持 try-with-resources 的类型示例

类型 是否支持 说明
InputStream / OutputStream ✅ 是 实现 Closeable
Reader / Writer ✅ 是 实现 Closeable
Socket ✅ 是 实现 Closeable
ServerSocket ✅ 是 实现 Closeable
RandomAccessFile ✅ 是 实现 Closeable
java.sql.Connection ✅ 是 实现 AutoCloseable
java.sql.Statement ✅ 是 实现 AutoCloseable
java.sql.ResultSet ✅ 是 实现 AutoCloseable
okhttp3.Response ✅ 是 实现 Closeable
java.util.zip.ZipFile ✅ 是 实现 Closeable
java.nio.channels.Channel ✅ 是 实现 Closeable
java.util.Scanner ✅ 是 实现 Closeable

❌ 不支持 try-with-resources 的示例

rust 复制代码
java
编辑
String str = "Hello";
try (str) { // ❌ 编译错误!String 没有实现 AutoCloseable
    // ...
}

try-with-resources 的语法形式

java 复制代码
// 单个资源
try (Resource resource = new Resource()) {
    // 使用 resource
} // 自动调用 resource.close()

// 多个资源(Java 7+)
try (Resource1 r1 = new Resource1();
     Resource2 r2 = new Resource2()) {
    // 使用 r1 和 r2
} // 按逆序自动关闭:r2.close() 然后 r1.close()

// 多个资源(Java 9+ 支持变量引用)
Resource1 r1 = new Resource1();
Resource2 r2 = new Resource2();
try (r1; r2) { // Java 9+ 允许直接使用已初始化的变量
    // ...
} // 自动关闭

⚠️ 重要特性

  1. 自动关闭

    • 无论 try 块是正常结束还是抛出异常,close() 方法都会被调用。
  2. 异常处理

    • 如果 try 块抛出异常,且 close() 方法也抛出异常,try 块的异常会作为主异常抛出,close() 的异常会被抑制(suppressed) ,可以通过 Throwable.getSuppressed() 获取。
  3. 关闭顺序

    • 多个资源时,按声明的逆序关闭(后声明的先关闭)。

建议

  • 当你需要使用需要手动关闭的资源时,优先考虑使用try-with-resource` 来简化代码和避免资源泄漏。
  • 可以在 try 的括号里声明多个资源,它们会按照声明的相反顺序依次关闭。

你可以尝试修改示例代码中的文件名,或者添加更多资源,进一步理解 try-with-resource 的用法。

相关推荐
天若有情67313 分钟前
【java EE】IDEA 中创建或迁移 Spring 或 Java EE 项目的核心步骤和注意事项
后端·spring·java-ee·intellij-idea
青云交15 分钟前
Java 大视界 -- Java 大数据在智能教育学习效果评估与教学质量改进实战
java·实时分析·生成式 ai·个性化教学·智能教育·学习效果评估·教学质量改进
崎岖Qiu17 分钟前
【设计模式笔记17】:单例模式1-模式分析
java·笔记·单例模式·设计模式
Lei活在当下1 小时前
【现代 Android APP 架构】09. 聊一聊依赖注入在 Android 开发中的应用
java·架构·android jetpack
不穿格子的程序员1 小时前
从零开始刷算法-栈-括号匹配
java·开发语言·
雪域迷影2 小时前
C#中通过get请求获取api.open-meteo.com网站的天气数据
开发语言·http·c#·get
lkbhua莱克瓦242 小时前
Java练习-正则表达式 1
java·笔记·正则表达式·github
yue0082 小时前
C#类继承
java·开发语言·c#
大鱼七成饱2 小时前
💥 从崩溃到稳定:我踩过的 Rust Tokio 线程池坑(含代码示例)
后端
喵个咪2 小时前
开箱即用的GO后台管理系统 Kratos Admin - 站内信
后端·微服务·go