紧接上篇Java 详解异常 Exception,入门到实践(一),再来看更优秀一点的处理方案,实际项目中如何处理这些异常。
前面使用throw
和throws
结合将异常对象抛出去
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/