Hi, 如果有任何想法与我沟通, 请用: lifr_nj 在 msn.com

如何处理异常: 以函数为中心

上一篇 / 下一篇  2010-09-16 15:39:02 / 个人分类:java

继续总结对异常处理的一些想法.

以函数为中心

处理异常的核心在函数. 函数是捕获异常情况, 抛出exception的地方.每一个函数都涉及健壮, 那么整个应用程序健壮性可期.

函数要处理好异常, 核心有三点
    1) 明确自己处理流程, 包括主流程和分支流程和异常流程. 这个相当于对调用者的一个"契约"
    2) 全面的异常情况的捕获/检查点
  1. 输入参数约束
  2. 系统本身的状态
  3. 外部系统的状态
  4. 调用下层library的返回值检查
  5. 调用下层library的exception捕获
    3) 合理的异常处理方法, 根据异常的"程度"高低, 适用的方法有
  1. Assert
  2. Runtime exception
  3. Named runtime exception with declaration
  4. General runtime exception without declaration
  5. checked exception
  6. return code

分类的异常情况的捕获和处理方法


1) 非法输入, 且检查责任在调用者 
如果检查非法输入完全是调用者的责任, 本函数只是为了自己的健壮性做出检查.
那么抛出NullPointerException, 或者IllegalArgumentExcedption. 这表明了调用者存在bug, 在调用此函数时没有作相应的检查.
比如 name 是空指针.
 

2) 非法输入,但检查责任在函数本身
这种情况应该纳入函数的"异常流"处理, 抛出有意义的exception, 可以用checked的exception, 也可以用named runtimeexception并且在函数签名里声明.
由于多用户操作引起的对象被删除, 一般来说这是"比较少见但不能杜绝的异常", 那么抛出一个general的service exception是合理的. 用户可以重新尝试.

如果检查非法输入不是调用者的责任, 本函数有责任检查输入是否合法 ,那么调用者应该知道调用为什么失败.
抛出有意义的Exception, 且这个exception从library的exception 层次里继承.
比如 throw new InvalidName("duplicated name")


3)  系统处于非法状态, 函数本身无法解决
这种情况一般表示本程序出现了bug, 应该马上退出程序. 保存现场, 而不应该继续提供任何服务.
用断言机制是比较简单的方法.

4)  系统处于非法状态, 函数可以恢复
函数尝试恢复. 在log里记录这个情况.

5) 底层系统的返回值
如果底层系统根据返回值来标示调用成功与否, 那么返回值一定是要检查的.

5)  底层library抛出exception
如果底层library抛出checked 异常, 那么捕获, 并抛出named runtime exception.
如果底层liabrary抛出none-checked异常, 一般不用捕获, 在最外层处理即可.

对于底层liabrary出现的异常要区分是由于外部系统(文件系统,数据库系统, ...)引起的, 还是应用程序本身的问题.
比如hibernate出现问题, 对于是connection错误, 还是查询的对象不存在是完全不同的异常.

5)  外部系统出现问题
这种情况一般系统本身不能处理, 能做的仅仅是体面的通知用户.
所以java io package里大量的checked IO exception是不好的设计.

6) 后置条件不满足
用到的很少.

异常处理不当导致的bug

  • 本来应该捕获的异常没有捕获, 导致系统在不正确的状态运行, 造成应用的不正确(比如数据丢失等)
  • 本来应该在A点捕获的异常没有捕获, 结果exception在B点或者下层library里抛出
  • 本来应该处理的异常没有处理/处理不正确, 导致用户的操作不能成功
  • 本来应该处理的异常没有处理/处理不正确, 用户在页面看到exception的原始信息
  • 本来应该处理的异常没有处理/处理不正确, 用户丢失了前期的工作成果(特别是提交form)
  • 本来应该处理的异常没有处理/处理不正确, 在log里看到error with stacktrace


TAG:

 

评分:0

我来说两句

Open Toolbar