异常处理 Exception 相关梳理
异常处理 涉及 到的基础语法
一、try {} catch(Exception e) {} finally {} throw throws
1、 普通场景
public void exec01() { System.out.println("方法开始"); try{ System.out.println("try 内方法"); int a = 1/0; System.out.println("错误后面的方法"); }catch (Exception e) { System.err.println("catch 内错误"); } System.out.println("catch 后的方法"); }
打印结果: 当程序执行到错误位置,跳转到 catch 内, 然后执行完 catch 后 程序继续执行。
2、 finally 的使用 , 保证在finally 代码块内的内容一定会执行(JVM 退出情况例外), 常用于释放资源等;
public String exec01() { System.out.println("方法开始"); try{ System.out.println("try 内方法"); int a = 1/0; System.out.println("错误后面的方法"); }catch (Exception e) { System.err.println("catch 内错误"); return "return 方法结束了"; }finally{ System.out.println("finally 执行到方法"); } System.out.println("catch 后的方法"); return "方法的最后一句话"; }
, 方法返回值:
3、 当方法内 throw 抛出异常后,如果执行到 throw 这一句,且外面调用此方法处无 try catch, 则系统报异常,并停止。
public String throw01() { System.out.println("方法开始"); try{ System.out.println("try 内方法"); int a = 1 / 0; System.out.println("错误后面的方法"); }catch (Exception e) { System.err.println("catch 方法内错误"); throw e; }finally { System.out.println("finally 代码块"); } System.out.println("finally 后面的方法"); return "方法的最后一句话"; }
3.1 、 直接调用throw01 方法会报错
3.2、 调用 throw02 方法则正常, finally 代码块的执行顺序可能在catch之前,之后,或者外部的catch 之前, 总之是保证一定能执行,但时间不定
public void throw02(){ try{ throw01(); }catch (Exception e) { System.err.println("throw02 catch 代码块"); }
System.out.println("throw02 方法异常后 代码块");
}
3.3、 当 finally 遇上返回值,执行顺序一样不定, 但执行的return 语句一定是finally 内的。
public String throw06() { try{ System.out.println("throw06 try 方法开始"); int a = 1/0; return "正常返回"; }catch (Exception e) { System.err.println("throw06 catch 代码块"); return "catch 代码块返回"; }finally { System.out.println("finally 代码块"); return "finally 代码块返回"; } }
3.4 、 如果直接抛出 new Exception() 则编译器本身会有提示,方法层必须 throws 出异常,以提醒调用此方法的代码去处理异常
public void throw03() throws Exception{ int a = 5; throw new Exception(); }
二、 自定义异常处理
有时候对于不同的异常我们需要区分,并且做不同的处理,此时就需要我们对异常进行分类,并在异常处理时对不同的异常进行分类处理
自定义异常类继承自 RuntimeException, 如下例:
public class BusinessException extends RuntimeException { private static final long serialVersionUID = 1L; private final String code; private final String msg; public BusinessException(String code, String msg){ super(msg); this.code = code; this.msg = msg; } public BusinessException(String code, String msg, Throwable t){ super(msg,t); this.code = code; this.msg = msg; } public String getCode(){return code;} public String getMsg(){return msg;} }
public class SystemException extends RuntimeException{ private static final long serialVersionUID = 1L; private final String code; private final String msg; public SystemException(String code, String msg){ super(msg); this.code = code; this.msg = msg; } public SystemException(String code, String msg, Throwable t){ super(msg,t); this.code = code; this.msg = msg; } public String getCode(){return code;} public String getMsg(){return msg;} }
异常处理类, @ControllerAdvice 这个注解将这个类标记为全局异常处理类, @ExceptionHandler 注解内是自定义异常类,抛出这个异常时,修饰的方法就会处理对应的异常
///** // * 全局异常处理 // * 为了方便前端处理,所有异常的 http状态码 返回200 // * // */ @ControllerAdvice @Slf4j public class GlobalExceptionHandler { /** * 业务异常处理,统一返回400状态码,后改为返回200 * * @param e * @param response * @return */ @ExceptionHandler(BusinessException.class) @ResponseBody public ExceptionResponse busExceptionHandler(BusinessException e, HttpServletResponse response) { log.info("Business Exception catched!", e); ExceptionResponse resp = new ExceptionResponse(); resp.setCode(e.getCode()); resp.setMsg(StringUtils.isBlank(e.getMessage()) ? "未知异常" : e.getMessage()); response.setStatus(HttpStatus.OK.value()); //400的异常统一返回200 状态码 return resp; } /** * 系统异常处理,统一返回500状态码 * * @param e * @param response * @return */ @ExceptionHandler(SystemException.class) @ResponseBody public ExceptionResponse sysExceptionHandler(SystemException e, HttpServletResponse response) { log.error("System Exception catched!", e); ExceptionResponse resp = new ExceptionResponse(); resp.setCode(e.getCode()); resp.setMsg(StringUtils.isBlank(e.getMessage()) ? "未知异常" : e.getMessage()); response.setStatus(HttpStatus.OK.value()); //400的异常统一返回200 状态码 return resp; } /** * 所有exception的处理 * * @param e * @param response * @return */ @ExceptionHandler(Exception.class) @ResponseBody public ExceptionResponse exceptionHandler(Exception e, HttpServletResponse response) { log.error("Exception catched!", e); ExceptionResponse resp = new ExceptionResponse(); if (e instanceof ServiceUnavailableException) { resp.setCode(ResponseCode.FAIL.code); resp.setMsg(ResponseCode.FAIL.msg); log.info(e.getMessage()); } else if (e instanceof HttpMessageNotReadableException || e instanceof MissingServletRequestParameterException || e instanceof MissingPathVariableException || e instanceof ServletRequestBindingException || e instanceof TypeMismatchException || e instanceof MissingServletRequestPartException || e instanceof HttpRequestMethodNotSupportedException) { resp.setCode(ResponseCode.BAD_REQUEST.getCode()); response.setStatus(HttpStatus.OK.value()); //0400的异常统一返回http 200状态码 resp.setMsg(StringUtils.isBlank(e.getMessage()) ? "请求参数有误!" : e.getMessage()); } else { resp.setCode(ResponseCode.FAIL.getCode()); response.setStatus(HttpStatus.OK.value()); resp.setMsg("系统异常!"); //统一返回“系统异常”,不将不可控的异常暴露给前端 } return resp; } }