你好,欢迎来到我的博客!我是【菜鸟不学编程】
我是一个正在奋斗中的职场码农,步入职场多年,正在从“小码农”慢慢成长为有深度、有思考的技术人。在这条不断进阶的路上,我决定记录下自己的学习与成长过程,也希望通过博客结识更多志同道合的朋友。
️ 主要方向包括 Java 基础、Spring 全家桶、数据库优化、项目实战等,也会分享一些踩坑经历与面试复盘,希望能为还在迷茫中的你提供一些参考。
我相信:写作是一种思考的过程,分享是一种进步的方式。
如果你和我一样热爱技术、热爱成长,欢迎关注我,一起交流进步!
虽然 Java 提供了很多现成的异常类(比如 NullPointerException
、IOException
、IllegalArgumentException
等),但是在实际项目里,你经常会遇到这样的问题:
标准异常不能准确表达业务错误。
例如:
NumberFormatException
又不是一回事)这些都是你的业务里 特定的错误,用系统内置异常,既不直观,也难以让调用者做精准处理。
这时,就需要你:
✅ 定义一个自己的异常类
✅ 在业务发生异常时抛出它
✅ 调用者捕获到后,才能做出针对性的处理
Java 异常分两大类:
必须用 try...catch
捕获,或者在方法签名 throws
抛出
例如:
IOException
SQLException
ParseException
不强制要求捕获或抛出
继承自 RuntimeException
例如:
NullPointerException
ArrayIndexOutOfBoundsException
IllegalArgumentException
自定义异常两种都可以做,但大部分时候业务异常习惯继承 RuntimeException,成为“运行时异常”。
原因是:
public class MyCheckedException extends Exception {
public MyCheckedException() {
super();
}
public MyCheckedException(String message) {
super(message);
}
public MyCheckedException(String message, Throwable cause) {
super(message, cause);
}
}
用法示例:
public void test() throws MyCheckedException {
if (true) {
throw new MyCheckedException("这是一个受检异常!");
}
}
调用者必须写 try-catch 或 throws:
try {
test();
} catch (MyCheckedException e) {
e.printStackTrace();
}
这是最常用的方式。
public class MyBusinessException extends RuntimeException {
public MyBusinessException() {
super();
}
public MyBusinessException(String message) {
super(message);
}
public MyBusinessException(String message, Throwable cause) {
super(message, cause);
}
}
用法示例:
public void createUser(String username) {
if ("admin".equals(username)) {
throw new MyBusinessException("用户名 admin 已存在!");
}
}
调用者可选择捕获,也可不捕获:
try {
createUser("admin");
} catch (MyBusinessException e) {
System.out.println(e.getMessage());
}
很多项目(尤其是微服务、REST API)喜欢在异常里带错误码,比如:
public class BusinessException extends RuntimeException {
private final String code;
public BusinessException(String code, String message) {
super(message);
this.code = code;
}
public String getCode() {
return code;
}
}
用法:
throw new BusinessException("USER_EXISTS", "用户已存在");
这样,前端收到响应就能根据 code
做精确处理,比如弹不同提示、走不同流程。
✅ 信息清晰
自定义异常的名字要能看出什么意思,比如:
UserNotFoundException
StockNotEnoughException
不要简单叫 MyException
或 TestException
。
✅ 带信息
最好至少写一个带 message 的构造函数:
public MyBusinessException(String message) {
super(message);
}
✅ 合理使用 RuntimeException
如果不是一定要强制捕获,推荐继承 RuntimeException
,写代码更轻松。
✅ 分层设计
在大型系统里:
BaseBusinessException
比如用户注册流程:
public class UsernameAlreadyExistsException extends RuntimeException {
public UsernameAlreadyExistsException(String username) {
super("用户名已存在:" + username);
}
}
业务逻辑:
public void register(String username) {
if ("admin".equals(username)) {
throw new UsernameAlreadyExistsException(username);
}
}
控制层统一处理:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UsernameAlreadyExistsException.class)
public ResponseEntity<String> handleUsernameExists(UsernameAlreadyExistsException ex) {
return ResponseEntity
.status(HttpStatus.CONFLICT)
.body(ex.getMessage());
}
}
这样,前端就能收到友好的提示。
RuntimeException
如果你觉得这篇文章对你有帮助,或者有任何想法、建议,欢迎在评论区留言交流!你的每一个点赞 、收藏 ⭐、关注 ❤️,都是我持续更新的最大动力!
我是一个在代码世界里不断摸索的小码农,愿我们都能在成长的路上越走越远,越学越强!
感谢你的阅读,我们下篇文章再见~