1.软件开发过程中,不可避免的是需要处理各种异常,就我自己来说,至少有一半以上的时间都是在处理各种异常情况,所以代码中就会出现大量的try {…} catch {…} finally {…} 代码块,不仅有大量的冗余代码,而且还影响代码的可读性。
2.使用统一结果处理时,有些异常我们可以提前预知并处理,但是一个运行时异常,我们不一定能预知并处理,这时可以使用统一异常处理,当异常发生时,触发该处理操作,从而保证程序的健壮性。
比较下面两张图,看看您现在编写的代码属于哪一种风格?然后哪种编码风格您更喜欢?
统一异常处理之后
上面的示例,还只是在Controller层,如果是在Service层,可能会有更多的try catch代码块。这将会严重影响代码的可读性、“美观性”。
所以如果是我的话,我肯定偏向于第二种,我可以把更多的精力放在业务代码的开发,同时代码也会变得更加简洁。
既然业务代码不显式地对异常进行捕获、处理,而异常肯定还是处理的,不然系统岂不是动不动就崩溃了,所以必须得有其他地方捕获并处理这些异常。
那么问题来了,如何优雅的处理各种异常?
异常分类(三大类)
2.未知异常(UnExpectedExceptionHandler)
3.数据合法性检查异常(ValidationExceptionHandler)
当出现异常时,异常处理的结果会包装到相应的Error对象中,包括错误代码code以及错误信息描述msg;
public static class Error {
@ApiModelProperty(value = "错误代码", name = "code", example = "TOKEN_001")
private String code = "";
@ApiModelProperty(value = "错误信息描述", name = "msg")
private String msg = "";
......
}
private boolean authenticate(String userId, String password) {
try {
service.login(userId, password);
} catch (PasswordWrongException e) { //按需处理,按需抛出
return false;
}
return true;
}
参数的格式校验由BeanValidation来处理,具体校验方式参见使用BeanValidation进行参数合法检查
@NotBlank(message = "{OFC_VALID_0008}")
@ApiModelProperty(value = "用户名", required = true)
private String userName;
BusinessException
的子类来完成处理,由Guava的Preconditions改写而成,目前框架定义的子类包含如下:BusinessIllegalArgumentException
、BusinessIllegalStateException
、BusinessNullPointerException
使用方式有以下两种:
第一种:使用BusinessPreconditions来完成
// 检查参数
BusinessPreconditions.checkArgument(checkResult, ErrorCode.LOGIN_FAILED.code(),
ErrorCode.LOGIN_FAILED.msg());
// 检查状态
BusinessPreconditions.checkState(checkResult, ErrorCode.USER_IS_LOCKED.code(),
ErrorCode.USER_IS_LOCKED.msg());
// 检查是否为空
BusinessPreconditions.checkNotNull(checkResult, ErrorCode.PASSWORD_IS_NULL.code(),
ErrorCode.PASSWORD_IS_NULL.msg());
第二种:自定义异常,编程显式抛出
public class PasswordWrongException extends BusinessException {
private static final long serialVersionUID = 1L;
public PasswordWrongException() {
super();
}
public PasswordWrongException(String message, Throwable cause) {
super(message, cause);
}
public PasswordWrongException(String s) {
super(s);
}
public PasswordWrongException(Throwable cause) {
super(cause);
}
}
//程序抛出
throw new PasswordWrongException(BusinessPreconditions.format(ErrorCode.PASS_ERROR.code(),
ErrorCode.PASS_ERROR.msg()));