【Java】try-with-resources 与异常处理最佳实践
大家好,今天继续分享 Java 基础干货,本次重点讲解try-with-resources语法,同时整理日常开发中 Java 异常处理的全套最佳实践,搭配代码示例,方便大家直接落地使用。
在传统 IO、网络连接、数据库连接等场景中,我们经常需要手动关闭资源。早期依靠try-catch-finally实现资源释放,代码冗余且容易出错,而try-with-resources的出现完美解决了这一痛点。
一、传统 try-catch-finally 回顾
在 Java 7 之前,所有流、连接类资源都需要在finally代码块中手动关闭,保证资源无论是否出现异常都能正常释放。
代码示例
import java.io.FileReader;
import java.io.IOException;
public class ResourceOldDemo {
public static void main(String[] args) {
FileReader reader = null;
try {
// 打开文件流资源
reader = new FileReader("test.txt");
char[] buf = new char[1024];
reader.read(buf);
System.out.println(new String(buf));
} catch (IOException e) {
e.printStackTrace();
} finally {
// 必须在finally中手动关闭资源
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
可以明显看到:关闭资源的嵌套 try-catch 让代码变得臃肿,一旦疏忽遗漏close()方法,就会造成资源泄漏。
二、try-with-resources 详解
Java 7 引入try-with-resources语法,核心作用是自动关闭实现了AutoCloseable接口的资源,无需手动在finally中调用关闭方法。
1. 基础语法使用
语法规则:在try后的括号内声明资源,程序执行完毕后,JVM 会自动调用资源的close()方法。
代码示例
import java.io.FileReader;
import java.io.IOException;
public class TryWithResourceDemo {
public static void main(String[] args) {
// 括号内声明资源,自动关闭
try (FileReader reader = new FileReader("test.txt")) {
char[] buf = new char[1024];
reader.read(buf);
System.out.println(new String(buf));
} catch (IOException e) {
e.printStackTrace();
}
// 无需写finally关闭资源
}
}
2. 管理多个资源
try-with-resources支持同时声明多个资源,多个资源用分号分隔,JVM 会按照声明的逆序依次关闭资源。
代码示例
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class MultiResourceDemo {
public static void main(String[] args) {
// 同时声明读、写两个流资源
try (FileReader reader = new FileReader("in.txt");
FileWriter writer = new FileWriter("out.txt")) {
char[] buf = new char[1024];
int len;
while ((len = reader.read(buf)) != -1) {
writer.write(buf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. 自定义资源(实现 AutoCloseable 接口)
想要让自定义类被try-with-resources管理,只需要实现AutoCloseable接口,重写close()方法即可。
代码示例
// 自定义资源类,实现AutoCloseable
class CustomResource implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("自定义资源已自动关闭");
}
public void work() {
System.out.println("自定义资源正在工作");
}
}
public class CustomResourceDemo {
public static void main(String[] args) {
try (CustomResource resource = new CustomResource()) {
resource.work();
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果:
自定义资源正在工作
自定义资源已自动关闭
4. 异常处理规则
如果try代码块和资源close()方法同时抛出异常,try-with-resources会将关闭时的异常标记为被抑制异常,主异常优先抛出,被抑制异常可通过getSuppressed()获取。
三、Java 异常处理最佳实践
结合日常开发规范与阿里 Java 开发手册,整理了一套通用的异常处理规范,规避常见坑点。
1. 尽量不捕获 RuntimeException
空指针、数组越界等运行时异常,不要通过catch捕获,优先使用前置校验规避。
❌ 不推荐:
String str = null;
try {
str.length();
} catch (NullPointerException e) {
e.printStackTrace();
}
✅ 推荐(前置校验):
String str = null;
if (str != null) {
str.length();
}
2. 资源关闭优先使用 try-with-resources
凡是流、连接等实现AutoCloseable的资源,统一使用try-with-resources,禁止手动在代码块内关闭资源。
3. 禁止捕获 Throwable
Throwable是Exception和Error的父类,捕获它会拦截系统级错误,严重影响程序稳定性。
❌ 错误写法:
try {
// 业务代码
} catch (Throwable t) {
t.printStackTrace();
}
4. 不要在 finally 中使用 return
finally一定会执行,如果其中写return,会覆盖try中的返回值,造成逻辑混乱。
5. 捕获具体异常,而非直接捕获 Exception
大范围捕获Exception会吞掉所有异常,不利于问题排查,精准捕获对应异常类型。
❌ 不推荐:
try {
// IO操作
} catch (Exception e) {
e.printStackTrace();
}
✅ 推荐:
try {
// IO操作
} catch (IOException e) {
e.printStackTrace();
}
6. 生产环境禁止使用 printStackTrace ()
线上环境必须使用日志框架(SLF4J、Logback、Log4j)记录异常,printStackTrace()仅用于本地测试。
7. 遵循「早抛出、晚捕获」原则
异常在底层代码尽早抛出,在上层统一捕获处理,保证异常上下文完整,方便定位问题。
8. 禁止用异常做流程控制
异常的设计初衷是处理意外错误,不能当作if/else、循环等流程判断工具,会严重降低代码性能与可读性。
四、总结
try-with-resources是 Java 7 推出的语法糖,依托AutoCloseable接口实现资源自动关闭,简化代码、杜绝资源泄漏,所有可关闭资源优先使用该写法。- 异常处理是 Java 开发的基础能力,严格遵循开发规范,拒绝滥用捕获、吞异常、乱用
printStackTrace()等陋习。 - 日常编码多注意细节规范,既能减少线上 Bug,也能让代码更易维护。



