• Java异常、SpringBoot中全局捕获处理异常


    Java异常

    首先程序错误分为三种:

    <pre class="hljs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 0.75em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">1/0
    

    继承结构

    首先异常的父类是 Throwable ,然后两个子类, Error 和 Exception 。其中Error(错误)是JVM中系统的异常,这些错误是不可控的,一般程序出现死循环或者线程死锁之类会导致出现此类错误。

    然后 Exception 中又分为两大类:运行时异常( RuntimeException )、非运行时异常( IO异常、SQL异常 等)。 运行时异常 这种系统异常可以处理也可以不处理,所以编译器不强制用try…catch处理或用throws声明。

    但是非运行时异常(又称编译异常),如IOException等,这种异常必须要显式的解决或抛出,要么自己try-catch解决,要么把异常抛出去交给jvm来解决,无论如何必须要处理这种异常。 编译器会强制让我们进行处理的 。

    那么可以得知:首先 Error中的错误 是我们无法手动处理的,只能通过优化代码等方式调整,然后 Exception中的RuntimeException 是可以不进行try-catch或throws处理的,那么某一层面上可以说这两种错误是 非受查异常 ,也就是编译器不会进行检查的异常。

    而 Exception中的IOException等 是编译器一定会进行检查且必须让我们手动处理(解决异常或抛出异常给jvm)被称之为 受查异常 。

    如何处理异常

    运行时异常(系统异常) 不需要预处理,通过规范的代码可以避免产生这种异常

    受检异常(编译时异常) 必须预处理,否则编译报错,有两种处理方式 :

    • 捕获处理
    • 抛出异常

    处理异常

    1. class="prettyprint hljs xquery" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">try { 
    2. } catch (OneException e) {
    3. } catch (TwoException e) {
    4. } finally {
    5. }
    • try中包含了可能产生异常的代码
    • try后面是catch,catch可以有一个或多个,catch中是需要捕获的异常
    • 当try中的代码出现异常时,出现异常下面的代码不会执行,马上会跳转到相应的catch语句块中,如果没有异常不会跳转到catch中
    • finally表示,不管是出现异常,还是没有出现异常,finally里的代码都执行,finally和catch可以分开使用,但finally必须和try一块使用

    而且要注意:假如有多个异常需要进行捕获,异常的捕获顺序是 先子类后父类 的,如下:

    1. class="prettyprint hljs xquery" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">try { 
    2. } catch (ChildException e) {
    3. } catch (ParentException e) {
    4. } finally {
    5. }

    抛出异常

    在定义方法时,如果方法体中有受检(编译时)异常需要预处理, 可以捕获处理 , 也可以抛出处理 。

    处理异常时,使用 throws 抛出处理:

    • 谁调用这个方法,谁负责处理该异常
    • 在定义方法时,把异常抛出就是为了提醒方法的使用者,有异常需要预处理

    在处理异常时,是选择捕获处理还是抛出处理

    • 一般情况下,在调用其他方法时,如果被调用的方法有受检(编译时)异常需要预处理,选择捕获处理,因为你调用了方法, 你负责处理该异常。
    • 在定义方法时,如果方法体中有受检异常需要预处理,可以选择捕获 ,也可以选择抛出处理。如果方法体中通过throw语句抛出了一个异常对象,所在的方法应该使用throws声明该异常。
    1. class="prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">// 声明方法时抛出异常,并且声明了一个异常,告知调用者
    2. public void show() throws Exception{
    3. throw new RuntimeException();
    4. }
    5. // 调用者需要继续 处理异常 或者 抛出异常
    6. public void test() throws Exception {
    7. show();
    8. }

    父子类中的异常

    子类中声明的异常的范围不能超过父类声明的异常范围:

    1. <pre class="hljs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 0.75em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><=

    如下错误实例:

    1. class="prettyprint hljs scala" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public class  A  { 
    2. // 父类抛出的IOException是Exception的子类
    3. public void show() throws IOException{
    4. }
    5. }
    6. class B extends A {
    7. // 这个方法会编译报错,不能抛出比父类方法范围大的异常
    8. @Override
    9. public void show() throws Exception {
    10. }
    11. }

    自定义异常

    为了封装异常和快速定位异常,我们可以自定义异常。

    自定义异常通常继承于 Exception 或 RuntimeException ,到底继承那个应该看具体情况来定。

    自定义异常类可以有自己的变量和方法来 传递错误代码 或 传递其它异常相关信息 。实际工作中,都会自定义异常类来处理异常。

    自定义非受查异常

    1. class="prettyprint hljs scala" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class  CheckedException  extends  Exception  { 
    2. public CheckedException() {
    3. // 调用父类的默认构造函数
    4. super();
    5. }
    6. public CheckedException(String message) {
    7. // 手动调用父类的构造方法
    8. super(message);
    9. }
    10. }

    自定义受查异常(常用)

    1. class="prettyprint hljs scala" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class  BusinessException  extends  RuntimeException  { 
    2. public BusinessException() {
    3. // 调用父类的默认构造函数
    4. super();
    5. }
    6. public BusinessException(String message) {
    7. // 手动调用父类的构造方法
    8. super(message);
    9. }
    10. }

    手动抛出异常(伪代码)。如在springboot项目中我们配置好全局捕获异常的增强后,可以直接在程序中抛出异常。如下涉及到一些业务逻辑。

    1. class="prettyprint hljs vbscript" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Order o = orderService.getById(5);
    2. if(Objects.isNull(o)) {
    3. throw new BusinessException("订单为空了");
    4. }

    抛出异常后,会被全局的捕获异常增强捕获,然后返回通用的数据格式给客户端。

    • 异常的分类

    • 两种异常分类的区别

    • 异常的5个关键字, try 、 catch 、 finally 、 throws 、 throw

    • 处理异常:捕获处理、抛出交给调用者处理

    • 异常捕获顺序,先捕获子类异常,再去捕获父类异常

    • 父子继承关系中方法重写要注意的,子类抛出异常的范围不能大于父类异常范围

    SpringBoot中如何处理异常

    在Java程序中我们知道:程序中可能出现的非受查异常或受查异常我们都可已进行处理(不包括Error错误),如使用try-catch进行捕获处理,或者直接抛出异常,让调用者处理。

    在SpringBoot项目中,由于要给客户端(前端)返回各种各样的数据,这些数据通常都是需要规定统一的数据格式进行返回,而当涉及到程序异常时,如何给客户端返回一些提示信息?

    定义一个异常类

    1. "prettyprint hljs java" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">@Data
    2. public class BusinessException extends RuntimeException{
    3. private static final long serialVersionUID = 1L;
    4. private String msg;
    5. private int code = 500;
    6. public BusinessException(String msg) {
    7. super(msg);
    8. this.msg = msg;
    9. }
    10. public BusinessException(String msg, Throwable e) {
    11. super(msg, e);
    12. this.msg = msg;
    13. }
    14. public BusinessException(String msg, int code) {
    15. super(msg);
    16. this.msg = msg;
    17. this.code = code;
    18. }
    19. public BusinessException(String msg, int code, Throwable e) {
    20. super(msg, e);
    21. this.msg = msg;
    22. this.code = code;
    23. }
    24. }

    SpringBoot配置全局异常捕获

    1. class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">@Slf4j
    2. @RestControllerAdvice
    3. public class GlobalExceptionHandler {
    4. @ExceptionHandler(Exception.class)
    5. public R handleException(Exception e, HttpServletRequest request) {
    6. log.error(request.getRequestURI() + ":服务运行异常------> {}", e);
    7. return R.buildFail("服务运行异常" + e.getMessage());
    8. }
    9. /**
    10. * 自定义异常处理
    11. */
    12. @ExceptionHandler(BusinessException.class)
    13. public R handleException(BusinessException e, HttpServletRequest request) {
    14. log.error(request.getRequestURI() + ":自定义内部异常------> {}", e);
    15. return R.buildFail(e.getMsg());
    16. }
    17. }

    在开发过程中,如果程序出现异常那么会报错抛出异常,那么我们直接用这个全局异常捕获到后,直接返回给客户端一个提示即可。

    实际上在开发中,我们都是自定义 RuntimeException 的子类异常(非受查异常),然后加以运用完善异常的处理机制。

     

  • 相关阅读:
    受出口和外国直接投资加速推动,中国 7 月外汇储备增加
    Python----科学计数法、同时给多个变量赋值、eval函数、math库函数、复数(complex())、内置的数值运算函数、内置的数值运算操作符
    antd的组件Form自定义提交的数据格式
    素数筛法及其优化策略
    智慧运维:基于 BIM 技术的可视化管理系统
    (0 , _login.default) is not a function ES6,小程序浮点数精度问题
    c#学习_第三弹
    设计模式——策略模式
    数学建模学习(104):线性回归和多元回归【补充版】
    java框架 Mybatis介绍与入门案例
  • 原文地址:https://blog.csdn.net/weixin_62421895/article/details/126314728