异常的继承体系
java 中的异常的超类是 java.lang.Throwable(后文省略为 Throwable), 他有俩自类Exception和Error,Error是由jvm管理,我们不需要考虑。
RuntimeException是Exception的子类。
-
检查异常(Checked Exceptions): 继承自 Exception 但不继承自 RuntimeException 的异常属于受检异常。必须通过 try-catch 块或者在方法签名中使用 throws 关键字来显式处理这些异常,否则编译器会报错。也称为“编译时异常”,编译器在编译期间检查的那些异常。由于编译器“检查”这些异常以确保它们得到处理,因此称为“检查异常”。
-
非受检异常(Unchecked Exceptions): 继承自 RuntimeException 的异常属于非受检异常。可以捕获处理或者向上传递。
RuntimeException 是非受检异常的根类,包括诸如 NullPointerException、ArrayIndexOutOfBoundsException、ArithmeticException 等运行时错误。通常,这些异常表示编程错误或者其他无法在编译时检测到的问题。
什么时候应该抛出异常?
抛出异常的目标是清晰地表达在程序执行期间发生的问题,并提供给上层调用者或者异常处理机制足够的信息以便进行处理或者修复。
- 特定的业务逻辑异常。例如,银行应用程序中的 InsufficientFundsException 表示账户余额不足。
- 状态机无法转向调用者提供的目标状态。
- 非法参数
应该选用哪种异常
通过以上的描述和举例,可以总结出一个结论,**RuntimeException 异常和受检异常之间的区别就是: 是否强制要求调用者必须处理此异常,如果强制要求调用者必须进行处理,那么就使用受检异常,否则就选择非受检异常 (RuntimeException)。**一般来讲,如果没有特殊的要求,我们建议使用 RuntimeException 异常。
实践
- 抛出带状态码 RumtimeException 异常
- 抛出指定类型的 RuntimeException 异常
服务中抛出什么样的异常就自定义一个指定的异常错误,然后在进行抛出异常。
异常设计的准则
-
不可以将异常处理作为系统流程的一部分。
-
避免过度细分异常,提高重用性。
-
避免过度使用 catch(Exception e) 来捕获所有异常。
-
不要同时记录和抛出异常,因为异常会打印多次,正确的处理方式要么抛出异常要么记录异常,如果抛出异常,不要原封不动的抛出,可以自定义异常抛出。
-
自定义异常不要丢弃原有异常,应该将原始异常传入自定义异常中。
throw MyException(“my exception”, e); -
自定义异常尽量不要使用检查异常。
-
尽可能晚的捕获异常,如非必要,建议所有的异常都不要在下层捕获,而应该由最上层捕获并统一处理这些异常。。
-
为了避免重复输出异常日志,建议所有的异常日志都统一交由最上层输出。就算下层捕获到了某个异常,如非特殊情况,也不要将异常信息输出,应该交给最上层统一输出日志。
应用程序中定义的异常应该分为两类:
业务异常:用户能够看懂并且能够处理的异常,比如用户没有登录,提示用户登录即可。
系统异常:用户看不懂需要程序员处理的异常,比如网络连接超时,需要程序员排查相关问题。
/**
* http 接口异常处理类
*/
@Slf4j
@RestControllerAdvice("org.example.controller")
public class HttpExceptionHandler {
/**
* 处理业务异常
* @param request 请求参数
* @param e 异常
* @return Result
*/
@ExceptionHandler(value = BizException.class)
public Object bizExceptionHandler(HttpServletRequest request, BizException e) {
log.warn("业务异常:" + e.getMessage() , e);
return Result.fail(e.getCode(), e.getMessage());
}
/**
* 处理系统异常
* @param request 请求参数
* @param e 异常
* @return Result
*/
@ExceptionHandler(value = SystemException.class)
public Object systemExceptionHandler(HttpServletRequest request, SystemException e) {
log.error("系统异常:" + e.getMessage() , e);
return Result.fail(e.getCode(), e.getMessage());
}
/**
* 处理未知异常
* @param request 请求参数
* @param e 异常
* @return Result
*/
@ExceptionHandler(value = Throwable.class)
public Object unknownExceptionHandler(HttpServletRequest request, Throwable e) {
log.error("未知异常:" + e.getMessage() , e);
return Result.fail(e.getMessage());
}
}
在 HttpExceptionHandler 类中,@RestControllerAdvice = @ControllerAdvice + @ResponseBody ,如果有其他的异常需要处理,只需要定义@ExceptionHandler注解的方法处理即可。