1 异常处理的重要性

  对于一个应用系统,设计一套良好的异常处理体系是很重要的,因为它对于程序的后期维护有十分重要的意义。

  应用系统的异常处理体系或者说框架,应该在系统设计初期的时候就考虑清楚,这样可以避免开发阶段由于异常处理体系的混乱而引起的不必要的重构工作。

  2 Java异常体系

  从类图中可以看出java异常的类继承关系,Throwable是所有异常和错误的父类。它的两个子类Error和Exception分别代表错误和异常。


  其中Exception又可以分为RuntimeException和非RuntimeException。

  RuntimeException也称为unchecked exception(不检查异常),非RuntimeException也称为checked exception(检查异常),它们之间的区别可以望文生义。

  不检查异常就是说程序中遇到这种异常的时候,程序可以不需要对这种异常进行处理,这种异常会自动地抛给JVM进行处理,不检查异常的例子有:NullPointException, IndexOutOfBoundsException;

  检查异常就是说程序中遇到这种异常的时候,程序需要对这种异常进行处理,检查异常的例子有:IOException, SQLException。对于检查异常,处理方式有三种:

  1. 采用try...catch...finally

  2. 直接throw给上层调用

  3. 对该异常进行捕获,然后将它封装成自定义的Exception,然后再throw给上层调用。

  3 Java异常处理经验

  3.1 项目现状

  1. 在实际的项目开发中,我们可能会在项目中依赖于各种各样的开源框架及工具,比如说Struts, Spring, Hibernate,JDBC等等,这些开源框架及工具的code在项目中被调用时,往往会抛出异常,比如说Hibernate的DataAccessException,JDBC的SQLException

  2. 在实际的项目开发中,一般会按照MVC设计模式对程序进行分层,分层之后,模型层code调用过程中产生的异常,各层除了对这个异常进行记录之外,无法作进一步的恢复处理。但是终端用户需要知道系统的运行结果,所以最后只能从视图层抛出一个错误消息提示框给终端用户:"Something went horribly wrong in our application; please contact the support desk."。

  也就是说如果模型层产生一个无法处理的checked exception,这个异常需要被层层抛出,最后在视图层捕获这个异常,然后给终端用户一个错误消息提示框。这很容易就使得程序变得混乱和难以维护。

  3.2 异常处理经验

  针对上面的情况,总结出一些应对的经验:

  1. 对于项目中依赖的开源框架及工具,事先调查清楚在调用时产生的异常。可以整理成如下异常表格:

  Exception NameResulting FromChecked or Unchecked ExceptionIs Client expected to recover(客户端捕获异常后,能否从异常中恢复)

  IOExceptionjava.ioChecked ExceptionNo

  SQLExceptionJDBCChecked ExceptionNo

  DataAccessExceptionHibernateChecked ExceptionNo

  ................

  经过调查之后可以发现,大部分的异常对于调用code来说,是无法从异常中直接恢复的,比如说指定文件无法找到而引起的IOException,数据库表字段类型不匹配而引起的SQLException等等。

  发生这些异常的位置一般比较底层。

http://yingchengfuzhuang.com  sducc1122

http://hainanqichewang.com  sducc1122

http://anshunzaixian.com  sducc1122

  发生这些异常之后,需要告诉终端用户类似于这个的错误信息:"Something went horribly wrong in our application; please contact the support desk."。

  2. 根据第一步中产生的异常表格,分成四种类型,及应对方法:

  checked Exception + could not be recovered类型:包装成用户自定义的RuntimeException,然后抛出。由于它属于RuntimeException,所以各层code不需要再对它进行try catch或throws声明。最后在视图层对该exception进行处理。

  checked Exception + could be recovered类型:层层抛出,需要再对它进行try catch或throws声明,最后在能处理的层进行捕获和恢复处理。

  unchecked Exception + could not be recovered类型:不用主动抛出,由于它属于RuntimeException,所以各层code不需要再对它进行try catch或throws声明。最后在视图层对该exception进行处理。

  unchecked Exception + could be recovered类型:不用主动抛出,由于它属于RuntimeException,所以各层code不需要再对它进行try catch或throws声明。最后在能处理的层对该exception进行捕获和恢复处理。

  在视图层,我们采用如下code来捕获一般异常:

  try {

  // code here

  }

  catch(UserDefinedException ex) {

  //dealing with exception here

  }

  catch (Exception ex) {

  //dealing with exception here

  }

  这样我们就可以在这里对checked Exception + could not be recovered类型(已经被包装成用户自定义的RuntimeException,并被抛出)及unchecked Exception + could not be recovered类型进行处理。其他两种类型:checked Exception + could be recovered类型及unchecked Exception + could be recovered类型都在能处理的层进行处理了。

  4 总结

  总结一下,异常处理框架在项目开发中是十分重要的。对于项目依赖的框架及工具所产生的异常,需要事先进行调查,对于项目自身的code可能产生的异常也需要事先调查,最后对这些异常进行分类处理。处理的方法根据异常类型的不同而有所差别,具体见3.2异常处理经验。

  这就是想要和大家分享的一点经验。希望对大家遇到异常处理时能有所帮助。由于水平有限,不对的地方欢迎大家批评指正。谢谢。