Java中的自定义异常类设计与应用
发布时间 - 2026-01-07 00:00:00 点击率:次自定义异常类必须继承Exception或RuntimeException,提供三个标准构造函数,不重写getMessage()和getCause(),命名体现业务语义而非技术细节,并配合@ControllerAdvice统一处理。
自定义异常类必须继承 Exception 或 RuntimeException
Java 中抛出自定义异常的前提是它得是 Throwable 的子类。绝大多数业务异常应继承 Exception(编译期检查异常),强制调用方处理;若属于程序逻辑错误(如参数非法、状态不一致),可继承 RuntimeException(运行时异常),避免处处 try-catch 或声明 throws。
常见错误是直接继承 Throwable 或空参构造不调用父类构造,导致堆栈信息丢失或序列化失败。
- 继承
Exception:适合需显式处理的业务场景,如支付超时、库存不足 - 继承
RuntimeException:适合开发阶段应避免发生的错误,如IllegalArgumentException的语义延伸 - 务必提供至少三个标准构造函数:
MyException()、MyException(String message)、MyException(String message, Throwable cause)
getMessage() 和 getCause() 不要被覆盖成空逻辑
自定义异常类中,除非有明确封装需求(如脱敏敏感字段),否则不要重写 getMessage() 或 getCause()。JVM 日志、IDE 调试、监控系统都依赖这些方法返回原始信息。
例如,以下写法会掩盖真实错误原因:
public class PaymentException extends Exception {
public PaymentException(String message) {
super(message);
}
@Override
public String getMessage() {
return "系统繁忙,请稍后再试"; // ❌ 隐藏原始 message,调试困难
}
}
正确做法是保留原始信息,必要时在日志中补充上下文:
- 用
super(message, cause)传递原始异常链 - 在
catch块中用log.error("支付失败,订单ID: {}", orderId, e)补充业务字段 - 避免在异常类内部做字符串拼接或格式化,交给日志层或调用方
异常类名要体现“什么错了”,而不是“怎么错的”
命名反映语义层级,而非技术路径。比如 InsufficientBalanceException 比 AccountBalanceCheckFailedException 更清晰;O 比
rderAlreadyShippedExceptionUpdateOrderStatusException 更准确。
容易踩的坑:
- 带动词或方法名(如
ValidateUserException)—— 这是动作,不是状态 - 含技术实现细节(如
JDBCConnectionTimeoutException)—— 应抽象为业务语义,如DatabaseUnavailableException - 用缩写或模糊词(如
InvldParamEx或BusinessError)—— 无法快速定位问题域
Spring 项目中配合 @ControllerAdvice 统一处理更实用
单独定义异常类意义有限,关键在于如何与框架协同。Spring MVC 中,自定义异常配合全局异常处理器能统一响应格式、HTTP 状态码和日志记录。
典型结构:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(InsufficientStockException.class)
@ResponseStatus(HttpStatus.PRECONDITION_FAILED)
@ResponseBody
public ApiResponse handleInsufficientStock(InsufficientStockException e) {
return ApiResponse.fail("库存不足", "STOCK_SHORTAGE");
}
}
注意点:
- 确保异常类在
@ExceptionHandler方法签名中精确匹配(不建议捕获Exception后再 instanceof 判断) - 避免在
@ExceptionHandler中抛出新异常,否则可能绕过统一处理逻辑 - 如果使用 Spring Boot +
ResponseEntityExceptionHandler,优先复用其默认行为,再针对性扩展
真正难的不是写一个异常类,而是让整个团队对每个异常的触发条件、恢复方式和日志埋点达成一致。名字、构造方式、是否检查、在哪捕获——这些决策一旦分散,就会变成排查时的噪音源。
# java
# 处理器
# 栈
# ai
# 状态码
# spring mvc
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
JavaScript中的标签模板是什么_它如何扩展字符串功能
如何在腾讯云服务器快速搭建个人网站?
如何在 Telegram Web View(iOS)中防止键盘遮挡底部输入框
Linux系统命令中tree命令详解
如何在七牛云存储上搭建网站并设置自定义域名?
百度浏览器ai对话怎么关 百度浏览器ai聊天窗口隐藏
Laravel的契約(Contracts)是什么_深入理解Laravel Contracts与依赖倒置
Laravel如何部署到服务器_线上部署Laravel项目的完整流程与步骤
Python制作简易注册登录系统
Laravel如何使用Scope本地作用域_Laravel模型常用查询逻辑封装技巧【手册】
大学网站设计制作软件有哪些,如何将网站制作成自己app?
实例解析angularjs的filter过滤器
制作旅游网站html,怎样注册旅游网站?
javascript中数组(Array)对象和字符串(String)对象的常用方法总结
nodejs redis 发布订阅机制封装实现方法及实例代码
如何在阿里云通过域名搭建网站?
Laravel怎么实现验证码功能_Laravel集成验证码库防止机器人注册
音乐网站服务器如何优化API响应速度?
Laravel怎么解决跨域问题_Laravel配置CORS跨域访问
Windows11怎样设置电源计划_Windows11电源计划调整攻略【指南】
Laravel如何配置和使用缓存?(Redis代码示例)
canvas 画布在主流浏览器中的尺寸限制详细介绍
Windows10怎样连接蓝牙设备_Windows10蓝牙连接步骤【教程】
Windows10如何更改计算机工作组_Win10系统属性修改Workgroup
Laravel中间件起什么作用_Laravel Middleware请求生命周期与自定义详解
JavaScript Ajax实现异步通信
php后缀怎么变mp4格式错误_修改扩展名提示格式不对怎么办【技巧】
安克发布新款氮化镓充电宝:体积缩小 30%,支持 200W 输出
Laravel如何实现本地化和多语言支持?(i18n教程)
网页设计与网站制作内容,怎样注册网站?
网站页面设计需要考虑到这些问题
如何用好域名打造高点击率的自主建站?
JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)
Laravel怎么上传文件_Laravel图片上传及存储配置
EditPlus中的正则表达式 实战(1)
C语言设计一个闪闪的圣诞树
Laravel控制器是什么_Laravel MVC架构中Controller的作用与实践
Laravel如何获取当前登录用户信息_Laravel Auth门面使用与Session用户读取【技巧】
北京专业网站制作设计师招聘,北京白云观官方网站?
原生JS实现图片轮播切换效果
做企业网站制作流程,企业网站制作基本流程有哪些?
Laravel如何实现API版本控制_Laravel API版本化路由设计策略
Laravel如何自定义分页视图?(Pagination示例)
作用域操作符会触发自动加载吗_php类自动加载机制与::调用【教程】
Laravel如何构建RESTful API_Laravel标准化API接口开发指南
如何用5美元大硬盘VPS安全高效搭建个人网站?
个人摄影网站制作流程,摄影爱好者都去什么网站?
Laravel如何使用Laravel Vite编译前端_Laravel10以上版本前端静态资源管理【教程】
JavaScript实现Fly Bird小游戏
微信小程序 canvas开发实例及注意事项

