1 前言

程序开发过程中, 对异常的处理机制是必须要考虑的问题. 下面是我基于之前的经验设计的一套方案.

程序执行过程分为三个阶段

  1. 输入
  2. 执行中
  3. 输出

因此,异常也分为三类

  1. 输入异常
  2. 执行中异常
  3. 输出异常

2 输入异常

输入异常,即验证输入值时发生的异常。此种异常往往由于以下几种情况导致:

  1. 系统数据异常。
  2. 非法的调用。

当此种异常发生时,不需要直接调用者做任何事情,因此可以使用非受验异常。

按照抛出异常代码所在层的不同,设置两种异常:

  1. 对外层(如controller层)ConrollerIllegalArgumentExceptio
  2. 内层(如service、dao层等) ServiceIllegalArguemtnException

2.1 抛出

2.1.1 对外层(如controller层)ConrollerIllegalArgumentException

对外层发生输入异常时,设置要返回给外层的提示信息并直接抛出对外层异常。

2.1.2 内层(如service、dao层等) ServiceIllegalArguemtnException

内层发生输入异常时,抛出内层异常。

2.2 处理

2.2.1 对外层(如controller层)ConrollerIllegalArgumentException

统一在调用栈的顶端拦截此异常,拦截对外层异常后,把对外层中的提示信息返回给外部。

2.2.2 内层(如service、dao层等) ServiceIllegalArguemtnException

拦截所有内层异常,执行以下流程:

  1. 保存错误跟踪信息。
  2. 设置要返回给外层的信息,设置要返回给外部的提示信息,包装并抛出对外层异常。

3 执行中异常 BusinessProcssRuntimeException

执行过程中如果发生了异常(注意,异常指的不是不同的程序分支),是由于以下几点原因导致的:

  1. 编程错误导致的运行时异常。
  2. 不可预知的外部(硬件故障,配置错误,文件丢失,服务器无法使用). 当这些情况发生时,并不需要直接调用者做任何事情(当然也不阻止它做一些处理工作),因此也同样使用非受验异常。

3.1 抛出

直接抛出执行中异常。

3.2 处理

在调用栈的顶部拦截执行中异常,执行以下流程:

  1. 保存错误跟踪信息。
  2. 向外层返回统一的提示信息。

4 输出异常 BusinessOutPutException

输出异常指的是,在程序流程执行完之后,没有得到预期的结果。 举例来说: 以用户登录为例。当使用输入的ID和PS在数据库中进行查询后,没能得到一个用户,那么这就是没有得到一个预期的结果。 而这种情况也分几种:

  1. 用户名是存在的,但是密码是错误的。
  2. 用户名不存在。

以上这些情况具有以下特点:

  1. 是可以预期的。
  2. 应该是设计中的一部分。
  3. 是异常,是程序流程中利用输入值得到的一种结果,并不是错误。
  4. 应该保证能够通知到直接调用者。

因此使用受验异常。

4.1 抛出

在得到的结果不是预期结果时,直接抛出输出异常。

4.2 处理

直接调用者需要拦截,并进行处理。

异常分为两种。

4.3 业务异常

程序执行流程中,除正常流程意外的其他流程发生时,称其为业务异常。

4.3.1 特点

  1. 业务异常是整个程序流程中的一部分,不是错误。因此如果出现业务异常,说明程序运行是没有问题的,并不需要进行修复。
  2. 需要保证调用者对其进行处理。(因此它是完整业务流程中的一部分)

4.4 程序错误

除了业务异常以外的情况。如果发生,那么就说明需要对程序进行修复。

4.4.1 特点

  1. 需要通知适合的人员。
  2. 需要保留错误信息,包括放生的时间、地点、事件。
  3. 程序能够体面地退出。

h + 如果有客户端,应该保证客户端操作者只能看到为他定制的信息,而不要把内部的详细错误信息露出(出于安全及用户体验的考虑)。

4.5 他们的比较

异常条件 意外事件 错误
认为是(Is considered to be) 设计的一部分 难以应付的意外
预期发生(Is expected to happen) 有规律但很少发生 从不
谁来处理(Who cares about it) 调用方法的上游代码 需要修复此问题的人员
实例(Examples) 另一种返回模式 编程缺陷,硬件故障,
    配置错误,文件丢失,服务器无法使用
最佳映射(Best Mapping) 已检查异常 未检查异常