java异常处理(初级)

转:http://blessht.iteye.com/blog/908286

从学习到现在从事java开发一年多了,个人觉得对java只了解皮毛,很多东西都是用到再去慢慢学习,编程真的是一项艺术,要完成一段好的代码,需要懂得很多。

最近项目经理让我负责一个组件开发,框架都由自己搭建,最让我头疼的是异常处理,我看了一些网上的源码,发现他们对异常的处理不是很重视,研究了很久都没有找到很好的解决方案。后来有幸看到一个200W美元的项目部分源码,通过他们对异常处理的解决方案,我终于弄通了java异常的一些基本机制,在这与大家分享一下。

 

(一)说到异常,首先从Throwable开始,Throwable是所有异常的基类,旗下有Error和Exception两个子类:Error属于程序无法控制的错误,通常不推荐捕获,捕获了你也处理不了;Exception就是我们熟知的可控制异常了。Exception旗下又分两种异常,运行时异常(RuntimeException)和非运行时异常:运行时异常是不需要强制捕获的,因为它随时随地可能发生,比如空指针异常(NullPointerException)和数组下标越界(IndexOutOfBoundsException);而非运行时异常在java里是需要你最终捕获的,不然编译都不通过,比如IO异常(IOException)和数据库错误(SqlException)。

 

下面来个例子:

①运行时异常数组下标越界(IndexOutOfBoundsException):

Java代码   收藏代码
  1. public class RuntimeDemo {  
  2.     public static void main(String[] args) {  
  3.         List<String> lst = new ArrayList<String>();  
  4.         lst.add("1");  
  5.         System.out.println(lst.get(10));  
  6.     }  
  7. }  

 

上面代码list里只有1条数据,但是我希望获取第11条数据,肯定会报异常的,但是我不需要捕获异常,因为结果是运行是异常,它会自动抛出异常:

Java代码   收藏代码
  1. Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 10, Size: 1  
  2.     at java.util.ArrayList.RangeCheck(ArrayList.java:547)  
  3.     at java.util.ArrayList.get(ArrayList.java:322)  
  4.     at demo.RuntimeDemo.main(RuntimeDemo.java:10)  

 

②非运行时异常,IoException为例:

Java代码   收藏代码
  1. public class IoDemo {  
  2.     public static void main(String[] args) {  
  3.         File f = new File("");   
  4.         try {  
  5.             f.createNewFile();  
  6.         } catch (IOException e) {  
  7.             e.printStackTrace();  
  8.         }  
  9.     }  
  10. }  

 

这里要求我必须捕获或者抛出,看结果:

Java代码   收藏代码
  1. java.io.IOException: 系统找不到指定的路径。  
  2.     at java.io.WinNTFileSystem.createFileExclusively(Native Method)  
  3.     at java.io.File.createNewFile(File.java:883)  
  4.     at demo.IoDemo.main(IoDemo.java:10)  

 

 

 

(二)异常的两种处理方式:抛出和捕获。

抛出异常表示当前的错误不在本方法中处理,交由调用当前方法的地方处理;捕获异常表示当前错误在本方法中通过catch捕获进行一些特殊处理。

①首先来看try...catch:

Java代码   收藏代码
  1. public class ThrowDemo {  
  2.     public void cathcMethod(){  
  3.         System.out.println("running cathcMethod...");  
  4.         File file = new File("");  
  5.         try {  
  6.             file.createNewFile();  
  7.         } catch (IOException e) {  
  8.             //直接在本方法把异常消化掉  
  9.             System.out.println("running cathcMethod's catch...");  
  10.         }  
  11.     }  
  12.       
  13.     public static void main(String[] args) {  
  14.         ThrowDemo td = new ThrowDemo();  
  15.         td.cathcMethod();  
  16.         System.out.println("running???????");  
  17.     }  

这里main函数里会运行cathcMethod方法,而该方法绝对会出现IOException异常,我们要看的是当运行完cathcMethod后,下面一句 System.out.println("running???????")是否会执行,看结果:

Java代码   收藏代码
  1. running cathcMethod...  
  2. running cathcMethod's catch...  
  3. running???????  

 

结果是,虽然td.cathcMethod();发生了异常,但是没有影响后面的代码的执行。这是因为当程序运行到cathcMethod方法时会发生IOException,但是cathcMethod方法通过catch直接捕获了异常,等于这个错误被该方法消化了,外面是不知道里面情况的。

这种捕获异常的方法通常是不可取的,因为你莫名其妙把这个重要的一个异常“吃”掉了,很可能会影响到一个系统的正常运作,通常我们会考虑抛出异常。

抛出异常需要说到两个关键字:throw和throws,这个东西口头不好说,直接代码说话:

Java代码   收藏代码
  1. public class ThrowDemo {  
  2.     /** 
  3.      *  
  4.      * Function  : 直接抛出异常 
  5.      * @author   : bless<505629625@qq.com> 
  6.      * @throws IOException 
  7.      */  
  8.     public void throwsMethod() throws IOException{  
  9.         System.out.println("running throwsMethod...");  
  10.         File file = new File("");  
  11.         file.createNewFile();  
  12.     }  
  13.       
  14.     public static void main(String[] args) throws IOException {  
  15.         ThrowDemo td = new ThrowDemo();  
  16.         td.throwsMethod();  
  17.         System.out.println("running??????");  
  18.     }  
  19. }  

 

throws写在方法后面,表示当前方法可能会出现的异常,一但加上了throws xxxException则该异常在方法体内就不需要用try...catch刻意捕获了(当然你也可以写,后面再说)。这个throws表示什么意思呢?它表示当运行当前方法时,可能会出现一个异常,但是当前方法不做处理,让调用该方法的地方去处理。我们看到main方法也有throws IOException ,这样再往上抛的话就到java虚拟机了,java虚拟机捕获到错误时就会打印错误信息到控制台,我们看结果:

Java代码   收藏代码
  1. running throwsMethod...  
  2. Exception in thread "main" java.io.IOException: 系统找不到指定的路径。  
  3.     at java.io.WinNTFileSystem.createFileExclusively(Native Method)  
  4.     at java.io.File.createNewFile(File.java:883)  
  5.     at demo.ThrowDemo.throwsMethod(ThrowDemo.java:16)  
  6.     at demo.ThrowDemo.main(ThrowDemo.java:21)  

 

我们看到上面运行了throwsMethod方法,但因为发生了异常终止了main方法里System.out.println("running??????");的执行,这是因为当运行到某个方法,该方法发生异常时候,如果该方法是throws了异常的,则该程序就只执行到发生异常的方法,然后把异常再往上处理。当然如果你在main函数里像厦门这样写,结果又不一样了:

Java代码   收藏代码
  1. public static void main(String[] args) {  
  2.         ThrowDemo td = new ThrowDemo();  
  3.         try {  
  4.             td.throwsMethod();  
  5.         } catch (IOException e) {  
  6.             System.out.println("running error...");  
  7.         }  
  8.         System.out.println("running??????");  
  9.     }  

 

 

 

 

(三)回头说说我正在开发的组件,后台三层Dao层(数据库操作)、Service层(业务操作)、Action层(实现页面交互),代码运行顺序依次是dao->service->action,action采用的是struts2框架,我的设计思想是dao和service对异常进行封装,到action层通过拦截器截获异常进行处理。为了明确发生了什么异常,个人建议使用自定义异常,通过自定义异常来处理各种错误。

首先看自定义异常代码:

Java代码   收藏代码
  1. public class SystemException extends RuntimeException{  
  2.     private static final long serialVersionUID = 1L;  
  3.       
  4.     String errorCode = "default";  
  5.   
  6.     public SystemException(){  
  7.         super();  
  8.     }  
  9.       
  10.     public SystemException(Throwable e){  
  11.         super(e);  
  12.     }  
  13.       
  14.     public SystemException(String message){  
  15.         super(message);  
  16.     }  
  17.       
  18.     public SystemException(String message,Throwable e){  
  19.         super(message,e);  
  20.     }  
  21.       
  22.                  public SystemException(String errorCode,String message){  
  23.           super(message);  
  24.           this.errorCode = errorCode;  
  25. }  
  26.   
  27.     /** 
  28.      * 最常用的构造方法 
  29.      * @param errorCode 错误ID 
  30.      * @param message   错误消息 
  31.      * @param e         异常信息 
  32.      */  
  33.     public SystemException(String errorCode,String message,Throwable e){  
  34.         super(message,e);  
  35.         this.errorCode = errorCode;  
  36.     }  
  37.       
  38.     public String getErrorCode() {  
  39.         return errorCode;  
  40.     }  
  41.   
  42.     public void setErrorCode(String errorCode) {  
  43.         this.errorCode = errorCode;  
  44.     }  
  45. }  

 

首先介绍几点我这个自定义异常:

①为什么继承RuntimeException: 因为RuntimeException是运行时异常,是不需要被捕获或强行抛出的,如果自定义异常继承Exception,后面方法都得捕获或throws,很麻烦。

②errorCode的作用:错误编号,这个是关键,因为系统可能会有很多种异常,我们可以给每种异常定义一个错误编号,然后在action层通过拦截器捕获自定义异常的errorCode,就可以知道是什么错误了。

 

再说Dao层使用的是spring封装过的类,spring把所有非运行时异常全部转换成了运行时异常。为了保证用户能明白执行什么,我会对每个方法捕获RuntimeException然后转换成自定义异常:

Java代码   收藏代码
  1. public class BaseDaoImpl extends HibernateDaoSupport implements BaseDao {  
  2.     public Object getObject(Class clazz, Serializable id)  
  3.             throws RuntimeException {  
  4.         Object o = null;  
  5.         try {  
  6.             o = getHibernateTemplate().get(clazz, id);  
  7.         } catch (RuntimeException e) {  
  8.             throw new SystemException("query_error","Sql exceptioin : query data error!",e);;  
  9.         }  
  10.         return o;  
  11.     }  
  12. }  

 其它层可能涉及到非运行时异常,比如action层ajax,后台可能会打印信息到页面,这时可能会有IOException:

Java代码   收藏代码
  1. PrintWriter out;  
  2.         try {  
  3.             out = response.getWriter();  
  4.         } catch (IOException e) {  
  5.             throw new SystemException("io_error","response.getWriter() error!",e);  
  6.         }  
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值