在Java开发中,当系统内置的异常类型无法准确表达业务场景中的错误情况时,我们就需要创建自定义异常并抛出,以此实现更精准的异常处理逻辑。自定义异常能够让我们根据业务需求定义特定的错误类型和错误信息,让代码的异常处理更具可读性和可维护性。
自定义异常的基本实现
Java中的所有异常都继承自Throwable类,我们自定义异常时通常选择继承Exception(受检异常)或者RuntimeException(非受检异常)。如果需要强制调用方处理该异常,就继承Exception;如果不需要强制处理,就继承RuntimeException。
自定义异常通常需要提供构造方法,用来传递错误信息,以下是一个继承Exception的自定义异常示例:
// 自定义受检异常
public class BusinessException extends Exception {
// 无参构造
public BusinessException() {
super();
}
// 带错误信息的构造
public BusinessException(String message) {
super(message);
}
// 带错误信息和原因的构造
public BusinessException(String message, Throwable cause) {
super(message, cause);
}
}
如果希望定义非受检的自定义异常,只需要将继承的父类换成RuntimeException即可:
// 自定义非受检异常
public class RuntimeBusinessException extends RuntimeException {
public RuntimeBusinessException(String message) {
super(message);
}
}
抛出自定义异常的语法
在Java中抛出自定义异常需要使用throw关键字,语法格式为throw 异常对象。如果是抛出的受检异常(继承Exception),还需要在方法声明处使用throws关键字声明该异常,告知调用方需要处理该异常;如果是非受检异常,则不需要在方法声明处声明。
抛出受检自定义异常示例
以下是一个业务场景中抛出受检自定义异常的示例,模拟用户年龄校验的业务逻辑:
public class AgeCheckService {
// 方法声明处使用throws声明抛出的受检异常
public void checkAge(int age) throws BusinessException {
if (age < 0 || age > 150) {
// 抛出自定义受检异常
throw new BusinessException("年龄输入不合法,请输入0到150之间的整数");
}
System.out.println("年龄校验通过,年龄为:" + age);
}
}
抛出非受检自定义异常示例
非受检自定义异常的抛出不需要在方法声明处添加throws,调用方可以选择处理也可以不处理:
public class OrderService {
public void createOrder(int quantity) {
if (quantity <= 0) {
// 抛出自定义非受检异常
throw new RuntimeBusinessException("订单数量必须大于0");
}
System.out.println("订单创建成功,数量为:" + quantity);
}
}
自定义异常的调用与处理
当调用可能抛出受检异常的方法时,必须使用try-catch块捕获异常进行处理,或者在当前方法上继续声明抛出该异常。以下是对上述年龄校验方法的调用示例:
public class TestDemo {
public static void main(String[] args) {
AgeCheckService ageCheckService = new AgeCheckService();
try {
ageCheckService.checkAge(200);
} catch (BusinessException e) {
// 处理捕获到的自定义异常
System.out.println("捕获到业务异常:" + e.getMessage());
}
OrderService orderService = new OrderService();
// 非受检异常可以选择不捕获,也可以选择捕获处理
try {
orderService.createOrder(-5);
} catch (RuntimeBusinessException e) {
System.out.println("捕获到运行时业务异常:" + e.getMessage());
}
}
}
自定义异常的注意事项
- 自定义异常的类名要尽量清晰,能够直观体现异常的含义,比如
UserNotFoundException、OrderPayFailedException等。 - 优先选择继承
RuntimeException定义非受检异常,避免不必要的try-catch代码,除非业务要求调用方必须处理该异常。 - 抛出自定义异常时,尽量提供清晰的错误信息,方便后续排查问题,也可以根据需要添加错误码等扩展属性。
- 不要在
catch块中直接抛出新的自定义异常而丢失原始异常信息,如果有原始异常,应该将其作为原因传入自定义异常的构造方法中。
合理的使用自定义异常能够让代码的异常处理逻辑更贴合业务场景,提升代码的可读性和可维护性,是Java开发中常用的技巧之一。