Java 详解异常 Exception,入门到实践(二)

紧接上篇Java 详解异常 Exception,入门到实践(一),再来看更优秀一点的处理方案,实际项目中如何处理这些异常。

前面使用throwthrows结合将异常对象抛出去

private static void testException(String s) throws NumberFormatException{
        try{
            Integer.parseInt(s);
        }catch(NumberFormatException e){
            throw new NumberFormatException();
        }
    }

从项目架构上分析,Service 层最有可能碰到异常,而且也是碰到异常最多的一层。上面用throw抛出异常对象后,我们一般会在Controller调用捕捉。但Service这边还需要多做一件事,打印错误日志保存起来,方便定位错误。代码修改如下:

private static void testException(String s) throws NumberFormatException{
        try{
            Integer.parseInt(s);
        }catch(NumberFormatException e){
        		Log.error("testException:" + e.toString());
            throw new NumberFormatException();
        }
    }

接着在Controller捕捉处理,返回给前端,当然,这个返回数据既要“友好”,也要符合封装好的数据。

public ResponseVO doTest(String s) {
        try {
            testException(s);
        } catch (NumberFormatException e) {
            return ResultUtil.error(e.getMessage());
        }
        return ResultUtil.success("测试成功");
    }

这就是整个处理流程,但还不够,这仅仅是系统异常,但项目都存在业务异常,这就需要自定义异常。普遍做法是定义一个基类异常,继承运行时异常RuntimeException,然后其他业务异常就继承这个基类自定义,记得将构造方法都提供出来。

public class BaseException extends RuntimeException {
    public BaseException() {
        super();
    }

    public BaseException(String message) {
        super(message);
        Log.error("" + message);
    }

    public BaseException(Throwable cause) {
        super(cause);
    }

    public BaseException(String message, Throwable cause) {
        super(message, cause);
    }

    public BaseException(ExceptionEnum exceptionEnum){
        Log.error("异常码:"+exceptionEnum.getCode()+exceptionEnum.getMsg());
    }
}

接着记得定义异常码,虽然可以在代码中明文使用,但不方便修改,而且如果项目未来要做中英文国际化,要找出词条并替换,非常麻烦。这里我创建枚举来接收异常码。

public enum ExceptionEnum {
    SIG_ERROR(4001,"签名错误");
    private int code;
    private String msg;
    ExceptionEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

再继承基类,创建自定义异常。

public class LoginException extends BaseException {
    private int code;
    private String message;

    public LoginException(ExceptionEnum exceptionEnum){
        super(exceptionEnum);
        this.code = exceptionEnum.getCode();
        this.message = exceptionEnum.getMsg();
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

代码中抛出异常就修改成如下:

 private static void testException4(String s) throws LoginException{
        try{
            Integer.parseInt(s);
        }catch(NumberFormatException e){
            throw new LoginException(ExceptionEnum.SIG_ERROR);
        }
    }

到现在,其实还有个疑问,也是被经常拿出来讨论的疑问,Service层中对于业务异常,到底使用return返回,还是抛出异常对象。

比如,业务异常大多能被判断出来,看下面伪代码。

	private void testException5(String s) throws LoginException{
        //做sql查询
        int m = doSQL(s);
        if(m != 0){
            
        }else{
            return object;
            //throw new LoginException(ExceptionEnum.SIG_ERROR);
        }
    }

到底是用return还是throw呢?

我的做法是能用return尽量用return,不方便使用才用throw

还有最后一个兜底的全局异常处理,万一有没被捕捉到的异常,也要考虑进来,不至于让程序崩溃。

一般结合Springboo的注解ControllerAdvice,以后再分享吧。

本文由老郭种树原创,转载请注明:https://guozh.net/java-exception-2/

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注