孤尽T31项目第5天-Java异常机制规约


前言

Java有很多优秀的语言特性和处理机制,但很少有人会提到异常处理机制,但是异常处理机制是Java中非常重要的组成部分,它对于保证我们系统的健壮性,可维护性等方面是非常重要的。
本文是对孤尽T31项目中学习Java异常处理机制的笔记,主要用作后续复习使用;本文涉及的案例,图片,代码等,大部分是训练课程的内容,不是本人原创,仅供参考学习;文中有出入的地方,欢迎各位大佬指正。

一、Java异常机制

1. 使用异常,日志为系统保驾护航

道路千万条,安全第一条,日志不规范,排查两行泪

  • 异常应当描述导致当前异常发生的原因
  • 根据异常栈应当能够快速定位到异常发生的位置
  • 结合异常描述和异常栈应当能解决异常

2. C语言的“异常”烦恼

在这里插入图片描述
以上c语言的异常处理有什么问题呢?

  • 代码可读性差,去掉注释的话,可读性就更差了
  • 当返回值与异常值相近时,容易混淆;例如定义了异常码1,2,3等,但刚好正确返回值也有这些数据,就需要额外了解所有返回值,保证异常码跟返回值不重复
  • 需要调用方来分析异常,增加多余的工作量;调用方同样也需要了解所有返回值代表的意思

3. Java异常处理流程

在这里插入图片描述

  • finally里发生的异常如何正确捕获和处理?
  • finally里发生了异常,没有捕获处理,也没有处理原异常,jvm会怎么处理2个异常呢?

4. Java异常处理机制

在这里插入图片描述
try代码块中抛出多种异常该怎么处理?

  • 加多个catch捕获所有可能的异常进行处理,每种异常处理流程不一致时采用这种
  • 分析多个异常是不是某一类子异常,并且后续处理办法是一致的,可以只抛出父类异常

5. Java异常体系

在这里插入图片描述
在这里插入图片描述

  • Error
    一般跟java虚拟机有关,比较致命的错误,如系统崩溃,虚拟机出错误等,通常应用程序无法处理的,Error也是不可检查的
  • 运行时异常
    是RuntimeException类及其子类异常,例如空指针异常,数组越界异常,除0异常等等,这类异常是不可检查的(编译器无法预计你写的程序逻辑有没有错误),程序可选择捕获或不捕获处理,一般都是由于程序逻辑错误引起的,用户也可以自定义可预测的业务运行时异常
  • 非运行时异常
    是RuntimeException以外的异常,如IOException、SQLException以及用户自定义异常等,这类异常是可检查的(可预计会发生的异常,而一旦发生就必须捕获处理的),编译器会检查它,要求必须catch,否则不可编译通过

异常处理有一条强制规约:在调用rpc或者二方包,或者动态生成类相关方法时,捕获异常必须使用Throwable,因为有可能抛出Error或者Exception

二、异常处理设计与实践

1. 异常抛出与捕获的原则

  • 非必要不使用异常
    异常捕获主要是针对非稳定性代码,生成异常对象和处理流程也是耗性能的,在稳定性代码中不必要try-catch,也不能大而全的try-catch,而只在有必要的语句中try-catch,主要对检查异常或自定义业务异常进行捕获处理
  • 使用描述性信息抛出异常
    例如上下文信息和参数,异常产生的原因,运行时环境等等
  • 力所能及的异常一定要处理,不要都往上抛出
  • 异常忽略要有理有据

2. try-catch-finally流程分析

在这里插入图片描述

  • 强制规约:不要在finally里写return语句
    try里的return不是立即返回结果,而是先放函数栈中,待finally语句块执行完后才返回,如果finally里有赋值给返回值变量,并且有return,则会忽略try里的返回值,如果没有return,则即使有赋值语句,也不会忽略try返回值

3. try with resource关闭资源的执行流程

在这里插入图片描述
在这里插入图片描述
上面代码有个问题,在关闭out的过程中发生异常的话,就不会再关闭FileOutputStream这个资源了,因为try with resource的机制只会关闭声明的2个资源,如下图来解决多资源的关闭
在这里插入图片描述
在这里插入图片描述

  • try()里的资源必须是实现了Closeable的
  • 资源是越晚使用到的,越早被关闭
    在这里插入图片描述
    上图中,a,b资源都有test方法并且里面抛出异常,也都有关闭资源的方法,当发生异常时,需要额外处理(上图选中的代码部分)才能看到a,b关闭方法里抛出的异常信息
    在这里插入图片描述无额外处理代码时打印的日志,只打印出a的test()的异常信息,a,b的close里的异常信息都没有打印出来
    在这里插入图片描述有额外处理代码的打印出来的日志

4. 特殊NPE场景及其处理对策

  1. 级联调用时易产生NPE
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
  2. foreach遍历集合的异常
    • 不要在foreach循环里进行元素的remove和add操作
    • foreach循环会自动跳过遍历空集合,如果有null值的集合,碰到null时注意NPE

三、日志设计

1. 日志的功能

在这里插入图片描述

2. 日志时效性规约

在这里插入图片描述

  • 记录用户敏感信息或操作日志为何要至少存储6个月,并多机备份?用什么级别日志输出?
    相关法律规定的,有一些金融方面要求保存可以更长,这是监管检查的原因;还有当发生一些纠纷的时候,可以拿出比较长时间的有效数据进行检查,作为证据,打官司等等处理;联机存储是为了防止丢失,人为损坏数据等原因;最好使用warn级别

3. 日志记录规约

  • 系统应依赖使用日志框架(SLF4J,JCL)的API而不是具体日志库的
    在这里插入图片描述日志框架大神Ceki Gulcu,主要有 Log4j、Logback 和 slf4j
    最早96年:log4j
    2002年:sun推出JUL,apache推出JCL
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述Slf4j绑定到各种日志库的流程
  • 在日志输出时,字符串变量之间的拼接方式使用占位符方式
  • 日志打印时禁止直接使用JSON工具将对象转换成String
  • 尽量用英文来描述日志错误信息 - 推荐

4. logback框架使用

  1. 核心配置对象及其属性分类
    在这里插入图片描述
  2. 关键类图分析
    在这里插入图片描述
  3. 线程模型分析
    在这里插入图片描述

5. 日志通知

在这里插入图片描述
在这里插入图片描述

6. 日志输出规约

  • 日志级别开关判断:对于trace/debug/info级别的日志输出,必须进行日志级别的开关判断
  • 异常日志信息要完整:包括2类信息,案发场景信息;异常堆栈信息
  • 避免重复打印日志:浪费磁盘空间,在日志配置文件中设置additivity=false
  • 扩展日志单独存储:如打点,临时监控,访问日志等
  • 错误日志单独存储:业务日志与错误日志分开存储

四、错误码设计

1. 错误码规约

  • 定义时要有字母也要有数字
  • 要分级分类管理
    在这里插入图片描述
    在完善的系统中甚至会开发错误码配置模块来管理
  • 不能直接输出给用户作为提示信息使用
  • 不要与业务架构或组织架构挂钩
  • 使用者避免随意定义新的错误码
  • 便于不同语言的开发者之间协作

五、异常处理和日志综合实践

1. 在Controller层统一捕获异常

在这里插入图片描述

  • 不是每一层都处理,都是往上层抛出,一般需要对异常信息,日志进行包装处理在抛出去
  • 在分布式部署多台机器时,异常日志则需要每层单独记录的,便于追溯来源和链路跟踪

2. 全局异常处理组件

在这里插入图片描述

3. API层异常设计实践

在这里插入图片描述

4. Service层异常设计实践

在这里插入图片描述

5. DAO层异常日志实践

  • 使用继承自RuntimeException的通用DaoException封装DAO层的异常并向上抛出
  • 在DAO框架层面有选择的记录数据操作的有效信息,比如:每次操作的原始sql语句以及其执行时间

6. 使用MDC实现轻量级调用链路跟踪

在这里插入图片描述

7. 使用有限的异常类处理业务中复杂多变的无限可能

  • 定义继承RuntimeException的通用ServiceException业务异常
  • 结合与业务关联的ErrorCode实现复杂多变的业务异常需求

8. 降低系统的维护难度,过度设计,冗余手段

  • 合理的领域划分
  • 通用模块单独拆分
  • 合适的工程结构
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值