接上篇:后端项目操作数据库-中枢组件Service调用Mapper
自定义异常: 手动抛出异常,为了后续统一捕获,需要异常自定义;
如:当使用抛出异常的方式表示“操作失败”时,为了后续统一捕获,自定义的异常符合该处理的情景。
1.RuntimeException检查异常&非检查异常
在 Java 中,RuntimeException 及其子类的异常被称为非检查异常(Unchecked Exception),而其他的异常(如 IOException 或 SQLException 等)则被称为检查异常(Checked Exception)。
对于非检查异常,通常是由程序员编写的代码错误引起的,如空指针异常或数组越界异常等。因此,如果程序出现这些异常,通常意味着程序的实现存在问题,需要在代码中进行改进。
相比之下,检查异常则需要在方法的声明或方法调用者的声明中声明抛出此异常。因为检查异常通常由外部因素(如文件操作、网络请求等)引起,并且需要在编写代码时考虑异常处理的情况。可能会导致程序无法正常工作,所以编码时必须将这些异常捕获或向上抛出来保证程序的稳定性和可靠性。
2.后端建议自定义异常,继承RuntimeException
自定义异常必须继承自某个已存在的异常类型,强烈建议继承RuntimeException,其原因有二:
原因1: 在项目中,要想统一处理全局异常,则Service组件、Controller组件都必须抛出异常,才能由Spring MVC框架捕获到异常,进而通过全局异常处理器进行统一的处理!
RuntimeException不会受到异常的相关语句约束,而非RuntimeException一旦被抛出,方法的声明、方法的调用者的声明等都需要声明抛出此异常。
由于抛出异常是固定的做法,没有必要在各个方法上都声明抛出此异常,所以,应该使用RuntimeException
原因2: 配合Spring JDBC框架实现事务管理!
3.异常分类
Java异常体系可以分为以下几个层次:
-
Throwable:Throwable 是所有异常的根类,它有两个直接子类 Error 和 Exception。
-
Error:Error 表示系统级别的错误或无法恢复的错误,一般在程序中不捕获和处理 Error,例如 OutOfMemoryError(内存不足)和 StackOverflowError(栈溢出)。
-
Exception:Exception 表示程序运行时的异常情况,是开发者通常需要处理的异常。Exception 下面又分为两种类型:RuntimeException 和非 RuntimeException。
-
RuntimeException:RuntimeException 是非检查异常,也称为运行时异常,它们不需要在编码时显式地处理或声明。常见的 RuntimeException 有 NullPointerException(空指针异常)和 ArrayIndexOutOfBoundsException(数组越界异常)。
-
非 RuntimeException:非运行时异常是必须进行显示的处理或声明的异常。这种异常是通过 Java 编译器检查的,编译器要求你必须捕获或向上抛出这些异常。常见的非 RuntimeException 有 IOException(输入输出异常)和 ClassNotFoundException(类未找到异常)。
根据这样的分类,开发者可以选择性地处理或声明异常。对于 RuntimeException,可以选择不捕获,而对于非 RuntimeException,必须在代码中显式地捕获或声明,否则程序无法通过编译。
4.自定义异常-举例
每次抛出异常,都应该是出现了某种“错误”,应该对此“错误”进行描述,关于此描述,应该是“谁抛出,谁描述”!
应该在自定义异常类中添加基于父类异常的带String message
参数的构造方法,例如:
public class ServiceException extends RuntimeException {
// 关键需要此构造方法
public ServiceException(String message) {
super(message);
}
}
后续,抛出异常时,应该通过以上构造方法封装对异常的描述:
// 检查相册名称是否已经被占用
String name = albumAddNewDTO.getName();
int countByName = albumMapper.countByName(name);
if (countByName > 0) {
String message = "添加相册失败,相册名称已经被占用!";
log.warn(message);
throw new ServiceException(message); // 【调整】在构造方法中封装message
}
后续,捕获异常的位置,将不再需要“猜测”出现异常的原因,而是从捕获到的异常对象中直接获取以上封装的描述信息即可:
try {
service.addNew(album);
log.debug("添加相册成功!");
} catch (ServiceException e) {
log.debug("捕获到异常,其中的消息:{}", e.getMessage()); // 【调整】从异常对象中获取信息
}
参考:异常体系之RuntimeException解析
声明:部分代码来自有网络,文章只供学习参考
创造价值,乐哉分享!