Java 异常机制

Java中的异常处理可以提高系统的健壮性以及用户体验。Throwable是所有异常和错误的父类,其继承结构如下:

a) Unchecked Exception
  非检查异常不要求程序员捕获,且可以由系统自动抛出, 如除法运算中除数为0时,程序自动抛出ArithmeticException的算术异常,而不用程序员手动抛出。RuntimeException表示代码本身存在BUG。

b) Checked Exception
  检查异常强制要求程序员捕获异常,否则编译不通过,假如将 SQLException 定义为非检测异常,开发人员可能不会捕获处理异常。这样操作数据发生异常时,会导致严重的 Connection 不关闭、Transaction 不回滚、DB 中出现脏数据等情况。将SQLException 定义为检测异常,才会驱使开发人员去显式捕捉,并且在代码产生异常后清理资源。当然清理资源后,可以继续抛出非检测异常,阻止程序的执行。检测异常大多可以应用于工具类中。

   Java提供的检查异常机制,使得调用时可以明确知道该函数必须用try-catch捕获,而不用查看源代码才知该函数中存在异常。

常见问题

1. 代码层次结构的污染

  上面的代码中直接抛出了检查异常,从代码耦合角度上看,调用层需显示捕获。根据设计隔离原则,可以使用非检测异常进行封装,使得调用层可以不受该函数影响。

public Order getOrderById(Long id) throw SQLException {
    //根据 ID 查询数据库
}

/* 改正后 */
public Order getOrderById(Long id) {
     try{
            //根据 ID 查询数据库
     }catch(SQLException e){
            throw new RuntimeException(SQLErrorCode, e);  //利用非检测异常封装检测异常,降低层次耦合
     }finally{
            //关闭连接,清理资源
     }
}

2. 将异常包含在循环语句块中

  异常处理会占用系统资源,应该将try-catch语句块提取到循环外面。比如A类中有个方法a包含try-catch语句块, 而B类中循环调用a方法,这就发生了如下的问题。

for(int i=0; i<100; i++){
    try{
    }catch(Exception e){
         //...
    }
}

3. 异常打印问题

  · 多层次打印问题,比如Dao层中打印了log, Service层中又打印一遍,这样不仅消耗系统性能,还使得日志更为混乱了。

  · 异常打印信息中可以添加一些参数信息如orderId,便于追踪。

4. 利用 Exception 捕捉所有潜在的异常

  如果try中可能抛出各种异常,只用一个Exception去捕捉异常,可能会丢失原始异常的有效信息。记录异常信息时,还可以使用errorCode记录状态,编译开发人员后期跟踪系统运行状态。

参考原文: http://www.codeceo.com/article/java-exception-misdirection.html

原文地址:https://www.cnblogs.com/anxiao/p/6737450.html