Java异常处理核心是分层捕获具体异常、在catch中执行有意义操作(如重试、日志、抛业务异常)、用try-with-resources确保资源释放、自定义异常封装上下文,目标是行为可预期、问题可追溯、影响可控制。

在 Java 中,try-catch 不只是“包住可能出错的代码”,而是构建容错能力的关键环节。真正稳健的异常处理,核心在于区分异常类型、明确恢复策略、避免掩盖问题,而非简单地打印堆栈或吞掉异常。
按异常类型分层捕获,不笼统 catch Exception
用 catch (Exception e) 会一锅端所有异常,包括本该中断程序的严重错误(如 OutOfMemoryError)或可预见的业务异常(如用户输入为空)。应优先捕获具体异常类:
- 对可恢复的检查型异常(如
IOException、SQLException),单独捕获并针对性处理(重试、降级、记录日志) - 对运行时异常(如
NullPointerException、IllegalArgumentException),通常反映逻辑缺陷,不应静默吞掉,而应记录详细上下文后抛出更易懂的业务异常 - 避免捕获
Throwable或Error子类(如StackOverflowError),它们代表 JVM 层面故障,程序通常无法安全恢复
在 catch 块中做有意义的事,而非空操作或仅 printStackTrace()
e.printStackTrace() 只适合本地调试,生产环境必须用日志框架(如 SLF4J)记录,并包含关键上下文信息:
- 记录异常级别(ERROR)、完整堆栈、发生位置(类+方法+行号)、相关业务参数(如订单ID、用户ID)
- 若可自动恢复(如网络超时),在 catch 中执行重试逻辑(配合指数退避)或切换备用服务
- 若不可恢复但需用户感知,抛出自定义业务异常(如
PaymentFailedException),由上层统一转为友好的提示语 - 绝不写
catch (Exception e) { }—— 这等于把崩溃藏起来,让问题更难定位
善用 try-with-resources 和 finally 确保资源可靠释放
文件流、数据库连接、网络套接字等资源未关闭会导致内存泄漏或连接耗尽。Java 7+ 推荐用 try-with-resources 自动管理:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 所有实现
AutoCloseable的资源(如FileInputStream、Connection)可直接声明在 try 括号内,JVM 保证无论是否异常都会调用close() - 若需在异常后执行清理动作(如解锁、重置状态),用
finally块;注意finally中也应加 try-catch 防止新异常覆盖原异常 - 避免在
finally中 return 或 throw —— 它可能屏蔽主流程的异常或返回值
用自定义异常封装上下文,提升可维护性
直接抛 RuntimeException("订单创建失败") 缺乏结构化信息。建议定义继承自 RuntimeException 的业务异常类:
- 构造函数接收错误码(如
ORDER_CREATE_TIMEOUT)、原始异常、关键参数(如orderId) - 提供
getErrorCode()、getDetails()等方法,便于统一监控告警或前端展示对应文案 - 全局异常处理器(如 Spring 的
@ControllerAdvice)可集中捕获这些异常,统一返回标准 JSON 格式响应
不复杂但容易忽略:异常处理的目标不是让代码“跑起来”,而是让系统在出错时行为可预期、问题可追溯、影响可控制。每一次 catch,都该回答三个问题:这个异常为什么会发生?我此刻能做什么?用户或运维需要知道什么?
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










