必须显式处理ioexception和sqlexception:捕获后合理应对(如重试、降级、清理)或向上声明;区分来源与类型,避免空catch;用try-with-resources确保资源释放;按dao/service/controller分层处理异常。

处理 IOException 和 SQLException 这类受检异常(checked exception),核心原则是:**不能忽略,必须显式处理**——要么捕获并合理应对,要么向上声明抛出。Java 强制你直面它们,这其实是对健壮性的保护,而非负担。
明确异常来源,针对性处理
不同异常代表不同层面的问题,混为一谈容易掩盖真实风险:
-
IOException 多来自文件、网络、流操作(如
FileInputStream.read()、Socket.getOutputStream().write())。常见原因是资源不可用、权限不足、连接中断。应优先考虑重试(如网络超时)、降级(如读取默认配置)、或清理资源(关闭流)。 -
SQLException 来自数据库交互(如
PreparedStatement.execute())。需区分错误类型:SQLState或getErrorCode()可判断是连接失败、主键冲突、超时还是语法错误。不要把所有 SQL 异常都当严重故障——例如唯一约束违反(`23505` in PostgreSQL)可能是正常业务逻辑分支。
避免空 catch 块和生吞异常
写 catch (IOException e) { } 或只打日志不处理,等于放弃防御。正确做法包括:
- 记录带上下文的错误日志(如操作对象、参数、堆栈),方便排查;
- 根据场景决定是否恢复:文件读取失败可返回默认值;数据库插入失败可回滚事务并提示用户;
- 必要时包装为更语义化的运行时异常(如
new DataAccessException("Failed to save user", e)),让上层统一处理,同时保留原始根因。
善用 try-with-resources 自动释放资源
涉及流、连接、语句等需要 close() 的资源,必须确保关闭,否则易引发内存泄漏或连接耗尽。传统 try-catch-finally 容易出错,推荐:
- 使用
try-with-resources(JDK 7+),自动调用close(),即使发生异常也保证执行; - 资源类必须实现
AutoCloseable(InputStream、Connection、Statement等均已实现); - 多个资源用分号分隔,关闭顺序与声明顺序相反(后声明的先关闭)。
try (Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement("INSERT ...");
ResultSet rs = ps.executeQuery()) {
// 执行逻辑
} catch (SQLException e) {
// 处理异常
}
区分“处理”与“传播”,按职责分层
不是所有层都该自己消化异常:
- DAO 层可捕获
SQLException,转换为数据访问层异常(如DataAccessException),屏蔽 JDBC 细节; - Service 层关注业务规则,遇到数据异常可决定重试、补偿或抛出业务异常(如
InsufficientBalanceException); - Controller/Web 层负责向用户反馈,将底层异常映射为 HTTP 状态码与友好提示(如 500 内部错误 / 400 参数错误),不暴露堆栈。










