Java零基础之自定义异常类!

你好,欢迎来到我的博客!我是【菜鸟不学编程】
   我是一个正在奋斗中的职场码农,步入职场多年,正在从“小码农”慢慢成长为有深度、有思考的技术人。在这条不断进阶的路上,我决定记录下自己的学习与成长过程,也希望通过博客结识更多志同道合的朋友。
  
  ️ 主要方向包括 Java 基础、Spring 全家桶、数据库优化、项目实战等,也会分享一些踩坑经历与面试复盘,希望能为还在迷茫中的你提供一些参考。
   我相信:写作是一种思考的过程,分享是一种进步的方式。
  
   如果你和我一样热爱技术、热爱成长,欢迎关注我,一起交流进步!

全文目录:

    • 1. 为什么要自定义异常?
    • 2. 异常体系回顾
      • ➤ Checked Exception(受检异常)
      • ➤ Unchecked Exception(运行时异常)
    • 3. 如何自定义异常类?
      • 【方式 1】继承 Exception (受检异常)
      • 【方式 2】继承 RuntimeException (运行时异常)
    • 4. 带错误码的自定义异常
    • 5. 最佳实践
    • 6. 实际项目中自定义异常的例子
    • ✅ 小结
    • 写在最后

1. 为什么要自定义异常?

虽然 Java 提供了很多现成的异常类(比如 NullPointerExceptionIOExceptionIllegalArgumentException 等),但是在实际项目里,你经常会遇到这样的问题:

标准异常不能准确表达业务错误。

例如:

  • 用户名已存在
  • 年龄输入不合法(但和系统内置的 NumberFormatException 又不是一回事)
  • 权限不足
  • 库存不足

这些都是你的业务里 特定的错误,用系统内置异常,既不直观,也难以让调用者做精准处理。

这时,就需要你:
✅ 定义一个自己的异常类
✅ 在业务发生异常时抛出它
✅ 调用者捕获到后,才能做出针对性的处理

2. 异常体系回顾

Java 异常分两大类:

➤ Checked Exception(受检异常)

  • 必须用 try...catch 捕获,或者在方法签名 throws 抛出

  • 例如:

    • IOException
    • SQLException
    • ParseException

➤ Unchecked Exception(运行时异常)

  • 不强制要求捕获或抛出

  • 继承自 RuntimeException

  • 例如:

    • NullPointerException
    • ArrayIndexOutOfBoundsException
    • IllegalArgumentException

自定义异常两种都可以做,但大部分时候业务异常习惯继承 RuntimeException,成为“运行时异常”。
原因是:

  • 不强制捕获,代码更简洁
  • 调用者可根据需要决定是否捕获

3. 如何自定义异常类?

【方式 1】继承 Exception (受检异常)

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();
    }
    

【方式 2】继承 RuntimeException (运行时异常)

这是最常用的方式。

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());
    }
    

4. 带错误码的自定义异常

很多项目(尤其是微服务、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 做精确处理,比如弹不同提示、走不同流程。

5. 最佳实践

信息清晰
自定义异常的名字要能看出什么意思,比如:

  • UserNotFoundException
  • StockNotEnoughException

不要简单叫 MyExceptionTestException

带信息
最好至少写一个带 message 的构造函数:

public MyBusinessException(String message) {
    super(message);
}

合理使用 RuntimeException
如果不是一定要强制捕获,推荐继承 RuntimeException,写代码更轻松。

分层设计
在大型系统里:

  • 定义一个父类:BaseBusinessException
  • 其他业务异常继承它,便于统一处理

6. 实际项目中自定义异常的例子

比如用户注册流程:

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
  • 名字要准确,带有明确业务含义
  • 可结合错误码,便于前后端交互

写在最后

如果你觉得这篇文章对你有帮助,或者有任何想法、建议,欢迎在评论区留言交流!你的每一个点赞 、收藏 ⭐、关注 ❤️,都是我持续更新的最大动力!

我是一个在代码世界里不断摸索的小码农,愿我们都能在成长的路上越走越远,越学越强!

感谢你的阅读,我们下篇文章再见~

你可能感兴趣的:(Java从入门到放弃,java,开发语言)