关于java异常及全局异常处理实现

关于java异常

一般来说,当程序遇到错误,应该尽量处理错误,然后按照正确的姿势退出程序。否则,你可以想象一下当客户使用系统的时候,突然系统异常,直接报了一堆用户不知道的代码提示,这是多么难堪的局面。

一、异常的结构

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

在这里插入图片描述

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

  1. Error

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

  2. Exception

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

  3. 注:

    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());
    }
}
  1. 假如上面程序都顺利执行,testB这里没有处理出错,则执行顺序是testA->testB->testC->testD
  2. 假如程序在testB方法中出现了处理错误,则testA方法是顺利执行的,testB方法则是执行失败,然后直接跳到catch里面了,不会执行testC方法,执行完catch的内容后,会执行finally的testD方法。

四、 常用的异常处理设计

  1. 异常枚举类

    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;
        }
    }
    
  2. 基础异常类

    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;
        }
    }
    
    
  3. 异常子类

    public class SQLException extends BaseException {
    
        public SQLException () {
            super(ExceptionCode.DATABASE_OPERATION_EXCEPTION);
        }
    }
    
  4. 全局异常处理

    @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);
        } 
    }
    
  5. 基础控制器类

    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;
        }
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值