程序员、Java后端、面试题、异常类型、日志
吐槽
最近看公司业务代码发现异常那块天天用,但理解不深啊
赶紧复习下,我还是有一颗学习的心
互联网项目一个异常、一个日志都非常重要,设计的不好后果很痛苦。
异常类型
Throwable有两个子类,Error和Exception
Checked Exception
Unchecked Exception
基本概念扫盲
- 异常和错误的区别是,异常是可以被处理的,而错误是没法处理的。
- Error也是unchecked exception,也是无法预先处理的。
- 所有checked exception都是需要在代码中处理的,它们的发生是可以预测的
check异常
如Exception /IOException
uncheck异常
RuntimeException及他的子类
check异常总结
- 编译保证,没catch或throws编译报错
- throw的是check异常就当前方法必须 throws Exception 或catch 住
- throw的是check异常throws Exception这个异常了,上层方法必须 catch
uncheck异常总结
- 公司的自定义异常类都是基础RuntimeException,然后配合异常枚举
- com.google.common.base.Preconditions#checkArgument(boolean, java.lang.Object) 公司大佬喜欢用这个异常工具,自己可以参考造一个出来
异常理解
编译错误案例代码
public static void throwChecked(int a) { if (a > 0) { //自行抛出Exception异常 //该代码必须处于try块里,或处于带throws声明的方法中 throw new Exception("a的值大于0,不符合要求"); } }
idea 会提示 :Unhandled exception: java.lang.Exception
正常异常案例代码
public static void throwChecked(int a)throws Exception { if (a > 0) { //自行抛出Exception异常 //该代码必须处于try块里,或处于带throws声明的方法中 throw new Exception("a的值大于0,不符合要求"); } }
企业自定义异常类
优秀IT企业里不是创建一堆自定义异常,而是异常类配合异常枚举来设计
一般业务系统自定义异常类不要少过3个
get/set方法我就省略了
public class WangException extends RuntimeException { /**错误码*/ private WangErrorCodeEnum errorCode; /**详细错误信息*/ private Map errorMap = new HashMap(); /** * 带参构造器. * @param errorCode */ public WangException(WangErrorCodeEnum errorCode) { super(errorCode.getDesc()); this.setErrorCode(errorCode); } /** * 带参构造器 */ public WangException(WangErrorCodeEnum errorCode, String message) { super(StringUtils.isNotBlank(message) ? message : errorCode.getDesc()); this.setErrorCode(errorCode); } /** * 带参构造器. * @param errorCode * @param errorContext */ public WangException(WangErrorCodeEnum errorCode, ErrorContext errorContext) { this(errorCode, findMessage(errorContext)); } /** * 带参构造器. * @param errorCode * @param errorMap */ public WangException(WangErrorCodeEnum errorCode, Map errorMap) { this(errorCode); this.errorMap = errorMap; } /** * 带参构造器. * @param errorCode * @param message */ public WangException(WangErrorCodeEnum errorCode, String message, Map errorMap) { super(StringUtils.isNotBlank(message) ? message : errorCode.getDesc()); this.setErrorCode(errorCode); this.errorMap = errorMap; } /** * 带参构造器. * * @param message */ public WangException(String message) { super(message); this.setErrorCode(WangErrorCodeEnum.UNKNOWN_SYS_ERROR); }
错误枚举
public enum WangErrorCodeEnum { SYS_ERROR("SYS_ERROR", "系统错误,请重试"), UNKNOWN_SYS_ERROR("UNKNOWN_SYS_ERROR", "未知的系统异常"),
高级点的异常枚举
有日志级别、是系统还是业务异常、日志是error还是warn、info等等
SYSTEM_ERROR("000", ErrorLevels.ERROR, ErrorTypes.SYSTEM, "系统异常"),
模板模式
异常从dao、service等等抛上来后,
需要把异常信息转换封装返回给前端、或rpc调用端等等
这里一般可以采用模板模式,把各种异常的catch 转换封装
业务代码里只要调用模板代码即可,什么异常转换、日志记录都统一管理,
业务代码干净多了,技术经理看到又可以加工资了
日志规范
生产上尽量把info、error、warn分清楚
切记不要都打到error里面了(很多公司对error非常敏感的)
异常日志打印尽量把 场景、异常具体原因、影响业务等等打清楚,
异常码异常描述尽量精细,
大型分布式项目中日志好不好
决定了下班早不早,
平时写业务代码习惯打印“其他异常”,生产出故障了就发现自己是多么的坑爹
分布式trace_id非常强大,后边我研究下整理整理