°

一个疑难异常的整个解决的流程

一、异常的结构

异常有一个共同的祖先Throwable,其关系结构如下

1.png

如图所见,Throwable有两个重要的子类,Error和Exception。

    Error

    Error代表的错误是程序无法处理的,这表示程序中出现了严重的问题,比如OutOfMemoryError、ThreadDeath,当出现这些错误,JVM一般会选择线程终止,因为他们超出了应用程序控制和处理的能力之外。

    Exception

    Exception代表的异常是程序可以处理的。Exception一般分为RuntimeException及其子类和此外的Exception及其子类两部分。运行时异常RuntimeException这部分,比如NullPointerException,这些异常是不可查异常,也就是程序中可以选择捕获处理,也可以不处理;非运行时异常这部分比如SQLException是可查异常,也即是必须捕获处理或者向上抛出。

    注:

    a. 可查异常checked exceptions

    是编译器要求必须处理的异常,要么用try-catch捕获处理,要么向上抛出,否则编译不通过。这些异常包括了除了RuntimeException和RuntimeException子类以外的这部分Exception。

    b. 不可查异常unchecked excetions

    是编译器不要求处理的异常,包括运行时异常RuntimeException及其子类和Error。

二、异常处理

    1.假如通过throw语句抛出异常,则该方法应该同时使用throws子句声明抛出的异常类型。如

  

public void test() throws RuntimeException {
    
    throw new MyRuntimeException();
}

    假如方法没有显示使用throw抛出异常,但是仍然可能抛出异常,也可以使用throws子句声明抛出异常的类型。
2.假如一个方法使用throws抛出异常,则方法的调用者必须检查处理异常或者向上抛出。3.如果是不可查异常,可以不适用throws子句声明抛出异常,也能通过编译,但是出现异常时仍然会被系统抛出。
4.假如是可查异常,那么必须使用try-catch捕获处理或者继续向上抛出,否则不能通过编译。
5.假如方法覆盖,则必须抛出和被覆盖方法抛出的异常是同一个异常或其子类异常。
6.假如所有方法都层层向上抛出,最终会由JVM处理,JVM将会打印异常消息和堆栈信息。

三、当发生异常时程序的执行

public void test() throws RuntimeException {
    try {
        testA(new A());
        testB(new B());//处理错误
        testC(new C());
    } catch (Exception e) {
        throw new MyRuntimeException();
    } finally {
        testD(new D());
    }
}
假如上面程序都顺利执行,testB这里没有处理出错,则执行顺序是testA->testB->testC->testD

假如程序在testB方法中出现了处理错误,则testA方法是顺利执行的,testB方法则是执行失败,然后直接跳到catch里面了,不会执行testC方法,执行完catch的内容后,会执行finally的testD方法。

四、 常用的异常处理设计

    异常枚举类

    public enum ExceptionCode {
        SUCCESS(0, "操作成功!"),

        PARAMETER_INCORRECT(100001,"参数不正确"),
        UNAUTHENTICATED(100002, "未经认证,请先登录"),
        UNAHTUORIZED(100003, "未经授权,请联系客服"),

        DATABASE_OPERATION_EXCEPTION(200001, "数据库操作异常"),

        WECHAT_REDIRECT_EXCEPTION(900001, "微信重定向异常"),
        WECHAT_FETCH_ACCESS_TOKEN_EXCEPTION(900002, "微信获取 Access Token 异常"),
        SAB_USER_NOT_FOUND(700001, "用户不存在"),
        SAB_ROLE_NOT_FOUND(700002, "角色不存在"),
        SAB_DEPARTMENT_NOT_FOUND(700003, "部门不存在"),
        LOGIN_USER_NOT_FOUNT(700004, "用户不存在"),
        LOGIN_USER_PASSWORD_WRONG(700005, "用户密码错误"),
        LOGIN_USER_AUTHENTICATION(700006, "用户认证失败"),
        LOGIN_FAILED(700007, "登录失败");

        private int code;
        private String msg;

        ExceptionCode(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }

        public int getCode() {
            return code;
        }

        public String getMsg() {
            return msg;
        }
    }
     

    基础异常类

    public class BaseException extends RuntimeException {

        protected int code;
        protected String msg;

        public BaseException(ExceptionCode businessCode) {
            super(businessCode.getMsg());
            this.code = businessCode.getCode();
            this.msg = businessCode.getMsg();
        }

        public BaseException(int code, String msg) {
            super(msg);
            this.code = code;
            this.msg = msg;
        }

        public int getCode() {
            return code;
        }

        public String getMsg() {
            return msg;
        }
    }

   

    异常子类

    public class SQLException extends BaseException {

        public SQLException () {
            super(ExceptionCode.DATABASE_OPERATION_EXCEPTION);
        }
    }

     

    全局异常处理

    @ControllerAdvice
    public class GlobalExceptionHandler extends BaseController {

        @ResponseStatus(HttpStatus.EXPECTATION_FAILED)
        @ResponseBody
        @ExceptionHandler(value = BaseException.class)
        public JSONObject handleBaseException(BaseException e) {
            return buildResponse(e.getCode(), e.getMsg(), null);
        }
        /*
         * SQLException是BaseException的子类,假如发生SQLException异常
         * 根据异常匹配规则是优先捕捉到SQLException异常的,所以是进入这个异常处理方法
         */
        @ResponseStatus(HttpStatus.EXPECTATION_FAILED)
        @ResponseBody
        @ExceptionHandler(value = SQLException.class)
        public JSONObject handleSQLException(SQLException e) {
            return buildResponse(e.getCode(), e.getMsg(), null);
        }
    }
     

    基础控制器类

    public class BaseController {

        public JSONObject buildResponse() {
            return buildResponse(ExceptionCode.SUCCESS, null);
        }

        public JSONObject buildResponse(Object data) {
            return buildResponse(ExceptionCode.SUCCESS, data);
        }

        public JSONObject buildResponse(ExceptionCode businessCode, Object data) {
            return buildResponse(businessCode.getCode(), businessCode.getMsg(), data);
        }

        public JSONObject buildResponse(int code, String msg, Object data) {
            JSONObject response = new JSONObject();
            response.put("code", code);
            response.put("msg", msg);
            response.put("data", data);
            response.put("time", System.currentTimeMillis());
            return response;
        }
    }

打赏
  喜欢