Java自定义异常与异常使用最佳实践

转载自


Java自定义异常与异常使用最佳实践

异常的分类
1. 非运行时异常(Checked Exception)
        Java中凡是继承自Exception但不是继承自RuntimeException的类都是非运行时异常。
2. 运行时异常(Runtime Exception/Unchecked Exception)
        RuntimeException类直接继承自Exception类,称为运行时异常。Java中所有的运行时异常都直接或间接的继承自RuntimeException。
        Java中所有的异常类都直接或间接的继承自Exception。
异常的处理
        一、对应非运行时异常,必须对其进行处理。处理方式有两种:
□使用try…catch…finally语句块进行捕获
□在产生异常的方法所在的方法声明throws Exception
        二、对于运行时异常,可以不对其进行处理,也可以对其进行处理。一般情况下都不对其进行处理。
在使用Java API的方法时会产生异常,由于实际的需要,我们需要创建和使用自定义异常。使用全新的异常类,应用到系统程序中。
在介绍自定义异常时,首要先谈谈什么要使用自定义异常,使用自定义异常的好处。创建自定义异常是为了表示应用程序的一些错误类型,为代码可能发生的一个或多个问题提供新的含义;可以显示代码多个位置之间的错误的相似处,也可区分代码运行时可能出现的相似问题的一个或多个错误,或给出应用程序中一组错误的特殊含义。
应用场景
       服务器的基本作用是处理与客户机的通信,若使用标准Java API(如java.io和java.net包中的类)来编写服务器,则可使编写的代码在多个位置抛出IOException。在设置服务器、等待客户机连接和获取通讯流时,可抛出IOException,在通信期间及试图断开连接时,也会抛出IOException。简而言之,服务器的各个部分都是引发IOException。
       对于服务器而言,这样IOException意义不尽相同。虽然由同一异常类型表示,但与各个异常先关的业务含义存在差异,报告和恢复操作也不相同。所以,可以将一个异常集与服务器配置和启动问题关联,将另一个异常集与客户机通讯的实际行动关联,将第三个异常集与服务器关闭任务关联。使用自定义异常,可采用对应用程序有意义的方式来灵活地表示错误。
为此,我们需要使用自定义异常来定为问题,定位问题与异常实际准确的位置。
自定义异常类过程
        1. 多数情况下,只需要继承异常类Exception, 经常需要定义一个或多个构造函数,以在对象中存储错误消息。
扩展:
□类java.lang.Throwable是所有异常类的基类,它包括两个子类:Exception和Error,Exception类用于描述程序能够捕获的异常,如ClassNotFoundException。Error类用于指示合理的应用程序不应该试图捕获的严重问题,如虚拟机错误VirtualMachineError
□自定义异常类可以继承Throwable类或者Exception类,而不要继承Error类。自定义异常类之间也可以有继承关系
□需要为自定义异常类设计构造方法,以方便构造自定义异常对象。
        在继承任何异常时,将自动继承Throwable类的一些标准特性,如:
□错误消息
□栈跟踪
□异常包装

        若要在异常中添加附加信息,则可以为类添加一些变量和方法。本例演示的自定义异常没有按照业务类型来命名,而是创建一个通用异常类,以retCd来区别发生异常的业务类型与发生位置,当然对于具体的retCd值,事先必须有具体的规定或说明。

[java]  view plain  copy
  1. /** 
  2.  * 多数情况下,创建自定义异常需要继承Exception,本例继承Exception的子类RuntimeException 
  3.  * @author Mahc 
  4.  * 
  5.  */  
  6. public class CustomerException extends RuntimeException {  
  7.   
  8.     private String retCd ;  //异常对应的返回码  
  9.     private String msgDes;  //异常对应的描述信息  
  10.       
  11.     public CustomerException() {  
  12.         super();  
  13.     }  
  14.   
  15.     public CustomerException(String message) {  
  16.         super(message);  
  17.         msgDes = message;  
  18.     }  
  19.   
  20.     public CustomerException(String retCd, String msgDes) {  
  21.         super();  
  22.         this.retCd = retCd;  
  23.         this.msgDes = msgDes;  
  24.     }  
  25.   
  26.     public String getRetCd() {  
  27.         return retCd;  
  28.     }  
  29.   
  30.     public String getMsgDes() {  
  31.         return msgDes;  
  32.     }  
  33. }  

2. 声明方法抛出自定义异常。为了使用自定义异常,必须通知调用代码的类:要准备处理这个异常类型。为此,声明一个或多个方法抛出异常。找到异常发生点,新建异常并加上关键字throw。

[java]  view plain  copy
  1. public class TestClass {  
  2.   
  3.     public void testException() throws CustomerException {  
  4.         try {  
  5. <p>           //..some code that throws <span style="font-family:SimSun;">CustomerException</span></p>      } catch (Exception e) {  
  6.             throw new CustomerException("14000001""String[] strs's length < 4");  
  7.         }  
  8.     }  
  9. }  

3.自定义异常测试操作。

[java]  view plain  copy
  1. public class TestCustomerException {  
  2.   
  3.     public static void main(String[] args) {  
  4.   
  5.         try {  
  6.             TestClass testClass = new TestClass();  
  7.             testClass.testException();  
  8.         } catch (CustomerException e) {  
  9.             e.printStackTrace();  
  10.             System.out.println("MsgDes\t"+e.getMsgDes());  
  11.             System.out.println("RetCd\t"+e.getRetCd());  
  12.         }  
  13.     }  
  14. }  
以下的自定义异常的最佳实践,摘自网络,经过参考扩展使用。
使用异常的最佳实践
  下面的部分我们列出了客户端代码处理 API 抛出异常的一些最佳实现方法。
  1. 记得释放资源
  如果你正在用数据库或网络连接的资源,要记得释放它们。如果你使用的 API 仅仅使用 unchecked exception,你应该用完后释放它们,使用 try-final。

[java]  view plain  copy
  1. public void dataAccessCode (){  
  2.     Connection conn = null;  
  3.     try{  
  4.         conn = getConnection ();  
  5.         ..some code that throws SQLException  
  6.     }catch(SQLException ex){  
  7.         ex.printStacktrace ();  
  8.     } finally{  
  9.         DBUtil.closeConnection (conn);  
  10.     }  
  11. }  
  12.  class DBUtil{  
  13.     public static void closeConnection  
  14.         (Connection conn){  
  15.         try{  
  16.             conn.close ();  
  17.         } catch(SQLException ex){  
  18.             logger.error ("Cannot close connection");  
  19.             throw new RuntimeException (ex);  
  20.         }  
  21.     }  
  22. }  

DBUtil 是一个关闭连接的工具类。最重要的部分在于 finally,无论异常发不发生都会执行。在这个例子中,finally 关闭了连接,如果关闭过程中有问题发生的话,会抛出一个 RuntimeException。
  2. 不要使用异常作控制流程之用
  生成栈回溯是非常昂贵的,栈回溯的价值是在于调试。在流程控制中,栈回溯是应该避免的,因为客户端仅仅想知道如何继续。
  下面的代码,一个自定义的异常 MaximumCountReachedException,用来控制流程。

[java]  view plain  copy
  1. public void useExceptionsForFlowControl () {  
  2.     try {  
  3.         while (true) {  
  4.             increaseCount ();  
  5.         }  
  6.     } catch (MaximumCountReachedException ex) {  
  7.     }  
  8.     //Continue execution }  
  9.  public void increaseCount ()  
  10.     throws MaximumCountReachedException {  
  11.     if (count >= 5000)  
  12.         throw new MaximumCountReachedException ();  
  13. }  

useExceptionsForFlowControl()使用了一个无限的循环来递增计数器,直至异常被抛出。这样写不仅降低了代码的可读性,也让代码变得很慢。记住异常仅用在有异常发生的情况。
  3. 不要忽略异常
  当一个 API 方法抛出 checked exception 时,它是要试图告诉你你需要采取某些行动处理它。如果它对你来说没什么意义,不要犹豫,直接转换成 unchecked exception 抛出,千万不要仅仅用空的{}catch 它,然后当没事发生一样忽略它。
  4. 不要 catch 最高层次的 exception
  Unchecked exception 是继承自 RuntimeException 类的,而 RuntimeException 继承自 Exception。如果 catch Exception 的话,你也会 catch RuntimeException。

[java]  view plain  copy
  1. try{  
  2. ..  
  3. }catch(Exception ex){  
  4. }  

上面的代码会忽略掉 unchecked exception。
  5. 仅记录 exception 一次
  对同一个错误的栈回溯(stack trace)记录多次的话,会让程序员搞不清楚错误的原始来源。所以仅仅记录一次就够了。

  总结:这里是我总结出的一些异常处理最佳实施方法。我并不想引起关于 checked exception 和 unchecked exception 的激烈争论。你可以根据你的需要来设计代码。我相信,随着时间的推移,我们会找到些更好的异常处理的方法的。

出处:http://blog.csdn.net/mahoking



后续的加深理解:

Java异常:选择Checked Exception还是Unchecked Exception?

https://blog.csdn.net/kingzone_2008/article/details/8535287





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值