异常体系介绍及SpringBoot全局异常处理解决方案

本文介绍了Java异常处理的基础知识,包括异常体系、异常分类,并详细阐述了全局异常处理的必要性和实现方式,提供了具体的GlobalExceptionHandler示例,展示了如何优雅地处理各种异常情况,提升代码的可维护性和用户体验。

0、前面文章说过最近公司搭建新系统,这次我们聊聊关于全局异常处理。

1、异常体系和分类

1.1、先说说异常体系

所有的异常都是继承Throwable而来,其中Throwable分为Error和Exception

Error是错误,对于所有的编译时期的错误以及系统错误都是通过Error抛出的。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时, 如Java虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java中,错误通过Error的子类描述。

Exception,是另外一个非常重要的异常子类。它规定的异常是程序本身可以处理的异常。Exception类分解成两个分支,一支派生于RuntimeException,另一支派生于其他异常。异常和错误的区别是,异常是可以被处理的,而错误是没法处理的。

1.2、异常分类

异常分类有可检查异常、不可检查异常 ;

可检查异常就是编译器要求你必须处置的异常。不知道你编程的时候有没有遇到过,你写的某段代码,编译器要求你必须要对这段代码try…catch,或者throws exception, 如果你遇见过,没错,这就是检查异常,也就是说,你代码还没运行呢,编译器就会检查你的代码,会不会出现异常,要求你对可能出现的异常必须做出相应的处理。

对检查异常(checked exception)的几种处理方式:

  • 1、继续抛出,消极的方法,一直可以抛到java虚拟机来处理,就是通过throws exception抛出。注意,对于检查的异常必须处理,或者必须捕获或者必须抛出

如何区分检查异常:除了RuntimeException与其子类,以及错误(Error),其他的都是检查异常(绝对的大家族)。

不可检查异常就是编译器不要求强制处置的异常,虽然你有可能出现错误,但是我不会在编译的时候检查,没必要,也不可能。为什么呢?你想想非检查异常都有哪些?NullPointerException,IndexOutOfBoundsException,VirtualMachineError等,这些异常你编译的时候检查吗?那我还要不要运行了,等死人啊。再说了,明明可以运行时检查,都在编译的时候检查,你写的代码还能看吗?而且有些异常只能在运行时才能检查出来,比如空指针,堆溢出等。

对未检查的异常(unchecked exception )的几种处理方式:

  • 1、继续抛出;
  • 2、不处理。 一般我们是不处理的,因为你很难判断会出什么问题,而且有些异常你也无法运行时处理,
    比如空指针,需要人手动的去查找。而且,捕捉异常并处理的代价远远大于直接抛出。

2、常见的异常

  • 输入输出异常:IOException
  • 算术异常类:ArithmeticExecption
  • 空指针异常类:NullPointerException
  • 类型强制转换异常:ClassCastException
  • 操作数据库异常:SQLException
  • 文件未找到异常:FileNotFoundException
  • 数组负下标异常:NegativeArrayException
  • 数组下标越界异常:ArrayIndexOutOfBoundsException
  • 违背安全原则异常:SecturityException
  • 文件已结束异常:EOFException
  • 字符串转换为数字异常:NumberFormatException
  • 方法未找到异常:NoSuchMethodException

3、现在说说统一处理异常的必要性:

  1. 避免try…catch过多,使得代码可维护性、可读性降低
  2. 统一出现异常后返回给前端的数据格式
  3. Validator参数校验器的时候,参数校验不通过会抛出异常,无法用try…catch捕获,只能使用全局异常处理器。

4、统一处理异常解决方案:

  • 统一异常拦截(GlobalExceptionHandler)、
  • 统一定义异常code枚举类(ExceptionCodeEnum)、
  • 统一定义业务异常通用类(BusinessException)。
@Slf4j
@Component
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
   
   @Override
   protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
   
   
   log.error("REST API exception handler got a message not readable exception, message:{},[request:{}]}", ExceptionUtils.getStackTrace(ex), request);
   log.info("参数不能读异常:{}\nat:{}", ExceptionUtils.getStackTrace(ex));
   return new ResponseEntity<>(Result.of(HttpStatus.UNPROCESSABLE_ENTITY.value(), ex.getMessage(), null, null), OK);
    }
    
    @Override
    protected ResponseEntity<Object> handleHttpMessageNotWritable(HttpMessageNotWritableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
   
   
    log.error("REST API exception handler got a message not writable exception:\n" + ExceptionUtils.getStackTrace(ex));
    return new ResponseEntity<>(Result.of(HttpStatus.UNPROCESSABLE_ENTITY.value(), ex.getMessage(), null, null), OK);
    }
    
    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(
    MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
   
   
    String message = ex.getFieldError().getDefaultMessage();
    String method = ex.getParameter().getMethod().getName
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白de成长之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值