首页 存档 技术 查看内容

Java异常处理的误区和经验总结分享

2018-3-30 13:00 |来自: 互联网 318 0

摘要: 以下内容转自:http://www.kuqin.com/shuoit/20161219/353182.html 本文着重介绍了 Java 异常选择和使用中的一些误区,希望各位小伙伴能够熟练掌握异常处理的一些注意点和原则,注意总结和归纳。只有处理好了异常, ...

以下内容转自:http://www.kuqin.com/shuoit/20161219/353182.html


本文着重介绍了 Java 异常选择和使用中的一些误区,希望各位小伙伴能够熟练掌握异常处理的一些注意点和原则,注意总结和归纳。只有处理好了异常,才能提升开发人员的基本素养,提高系统的健壮性,提升用户体验,提高产品的价值!


误区一、异常的选择

图1. 异常分类


图1描述了异常的结构,其实我们都知道异常分检测异常和非检测异常,但是在实际中又混淆了这两种异常的应用。由于非检测异常使用方便,很多开发人员就认为检测异常没什么用处。其实异常的应用情景可以概括为以下:


一、调用代码不能继续执行,需要立即终止。出现这种情况的可能性太多太多,例如服务器连接不上、参数不正确等。这些时候都适用非检测异常,不需要调用代码的显式捕捉和处理,而且代码简洁明了。


二、调用代码需要进一步处理和恢复。假如将 SQLException 定义为非检测异常,这样操作数据时开发人员理所当然的认为 SQLException 不需要调用代码的显式捕捉和处理,进而会导致严重的 Connection 不关闭、Transaction 不回滚、DB 中出现脏数据等情况,正因为 SQLException 定义为检测异常,才会驱使开发人员去显式捕捉,并且在代码产生异常后清理资源。当然清理资源后,可以继续抛出非检测异常,阻止程序的执行。根据观察和理解,检测异常大多可以应用于工具类中。


误区二、将异常直接显示在页面或客户端。


将异常直接打印在客户端的例子屡见不鲜,以 JSP 为例,一旦代码运行出现异常,默认情况下容器将异常堆栈信息直接打印在页面上。其实从客户角度来说,任何异常都没有实际意义,绝大多数的客户也根本看不懂异常信息,软件开发也要尽量避免将异常直接呈现给用户。


清单1

 package com.ibm.dw.sample.exception;/** * 自定义 RuntimeException * 添加错误代码属性 */public class RuntimeException extends java.lang.RuntimeException { 
   //默认错误代码 
  public static final Integer GENERIC = 1000000; 
  //错误代码
  private Integer errorCode; 
   public RuntimeException(Integer errorCode, Throwable cause) {      this(errorCode, null, cause);
   }   public RuntimeException(String message, Throwable cause) {      //利用通用错误代码
      this(GENERIC, message, cause);
   }   public RuntimeException(Integer errorCode, String message, Throwable cause) {      super(message, cause);      this.errorCode = errorCode;
   }   public Integer getErrorCode() {      return errorCode;
   } 
}


正如示例代码所示,在异常中引入错误代码,一旦出现异常,我们只要将异常的错误代码呈现给用户,或者将错误代码转换成更通俗易懂的提示。其实这里的错误代码还包含另外一个功能,开发人员亦可以根据错误代码准确的知道了发生了什么类型异常。


误区三、对代码层次结构的污染


我们经常将代码分 Service、Business Logic、DAO 等不同的层次结构,DAO 层中会包含抛出异常的方法,如清单 2 所示:


清单 2

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

上面这段代码咋一看没什么问题,但是从设计耦合角度仔细考虑一下,这里的 SQLException 污染到了上层调用代码,调用层需要显式的利用 try-catch 捕捉,或者向更上层次进一步抛出。根据设计隔离原则,我们可以适当修改成:


清单3

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


误区四、忽略异常


如下异常处理只是将异常输出到控制台,没有任何意义。而且这里出现了异常并没有中断程序,进而调用代码继续执行,导致更多的异常。


清单4

 public void retrieveObjectById(Long id){  try{    //..some code that throws SQLException
  }catch(SQLException ex){   /**    *了解的人都知道,这里的异常打印毫无意义,仅仅是将错误堆栈输出到控制台。    * 而在 Production 环境中,需要将错误堆栈输出到日志。    * 而且这里 catch 处理之后程序继续执行,会导致进一步的问题*/

     ex.printStacktrace();
   }
}

可以重构成:


清单5

public void retrieveObjectById(Long id){ try{  //..some code that throws SQLException
 } catch(SQLException ex){  throw new RuntimeException(“Exception in retieveObjectById”, ex);
 } finally{  //clean up resultset, statement, connection etc
 }
}


误区五、将异常包含在循环语句块中


如下代码所示,异常包含在 for 循环语句块中。


清单 6

for(int i=0; i
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部