处理Java异常的不定法则

由于天天写bug,代码里各个地方充斥着对异常的处理,有时候思路被卡住:这个地方是该抛异常呢,还是我就地解决?是抛出受检异常(Exception)还是抛出非受检异常(RuntimeException)呢?这个异常带不带状态码啊?常常在想,有没有什么好的定律可以指导我优雅地处理Java异常。

目前项目中常见的抛异常的做法是

public interface IExceptionCode {
    String name();
    String getMessage();
}

public enum AccountExceptionEnum implements IExceptionCode {
    // 枚举名就是状态码
    ACCOUNT0001("验证码错误");

    private String message;

    AccountExceptionEnum(String message) {
        this.message = message;
    }

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

public class ServiceException extends Exception {
    private String code;

    public ServiceException(String message) {
        super(message);
    }

    public ServiceException(String code, String message) {
        this(message);
        this.setCode(code);
    }

    public ServiceException(String code, String message, Throwable cause) {
        super(message, cause);
        this.setCode(code);
    }

    public ServiceException(String code, Throwable cause) {
        super(cause);
        this.setCode(code);
    }

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

    public String getCode() {
        return this.code;
    }
}

// 定义特定异常
public class AccountServiceException extends ServiceException {
    public MarsServiceException(String message) {
        super(message);
    }

    public MarsServiceException(IExceptionCode message) {
        super(message.getMessage());
        super.setCode(message.name());
    }
}

抛出带状态码的特定受检异常:

throw new AccountServiceException(AccountExceptionEnum.ACCOUNT0001);

这些特定ServiceException类型的异常都抛到了前端,异常序列化后的字符串:

{
    "code": "ACCOUNT0001",
    "message": "验证码错误",
    "data": null
}

每次要抛出一个业务异常的时候,都要写一个code和message,当业务流程校验比较复杂的时候,就要在AccountExceptionEnum里定义很多的code、message。感觉不爽的是,这大量的code码没有产生业务意义,觉得很冗余。还有项目中异常的使用也比较乱。

那来给寄几定义几个使用异常的不定法则吧,从此寄几再也不用担心我使用异常了。

一、业务性api、open api、soa接口层抛出特定的受检(Exception)异常,不抛非受检异常(RuntimeException)

api接口和soa接口声明受检异常,抛出特定受检异常(比如上面定义的AccountServiceException),这样controller层对异常的序列化也比较方便,清晰明了,就告诉你我会抛出这种类型的异常,你小心点。

二、状态码有业务意义,才抛出带状态码的异常
1. 开放平台的open api接口

开放平台的open api接口产生的异常都要带上状态码,以便第三方平台调用的识别。

2、一般业务系统api接口

将项目中的异常分成两类,有状态码和没有状态码。将状态码抛出去一定得是有业务意义的,不然就直接将错误message抛给前端就好了。秉承的原则就是不要写一点多余的代码。

3、soa接口

服务之间的调用,原则和2中所说一样。

4、业务方法

只抛带错误message的异常。

三、以fail fast为原则,需要fail fast情景抛出非受检异常(RuntimeException);其他情况抛出受检异常(Exception)

使用guava的Preconditions(checkNotNull、checkArgument……)或jsr 303(@NotNull、@NotBlank、@NotEmpty……)这种类似校验都抛出非受检异常(RuntimeException)。这些校验符合fail fast原则,你要不满足这些条件我就马上让你失败,啥也捞不到,并且也不告诉你要抛出什么类型的异常。剩下的就是业务逻辑的校验,抛出受检异常。

在目前的工作过程中,我总结出这三个不定法则,觉得这样做会少些麻烦、方便处理、少写代码,有了规则,让项目的后续开发以及维护都变得比较便利了。

如有不妥,欢迎拍砖。

参考文章:
如何优雅的设计 Java 异常
Java异常(二) 《Effective Java》中关于异常处理的几条建议

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值