现在的位置: 首页 > 综合 > 正文

java的异常机制分析

2013年10月19日 ⁄ 综合 ⁄ 共 3259字 ⁄ 字号 评论关闭

以下内容不完全是自己的原创,有参考了http://www.cnblogs.com/jing8100/archive/2010/04/02/1703037.html 这个网友的

  JAVA的异常,对应什么是异常,我就不多说,主要是讲异常使用的时候需要注意些什么,异常是很简单一件事情,别被网上很多讲迷惑了 

java的异常层次:

   

    

从上图可以看到 Throwable是父类,它直接从Object基类继承了,下面派生出两种类别,一种是Error,一种是Exception

Error :一般的程序是不需要关心的,但是如果你不按照常规,在自己的程序抛出Error,然后try,catch进行处理的话 也是成功的,因为Error是继承Throwable,try catch( Throwable e) ,所以对Error来说也是可以捕获到的,都是运行时异常(后面有讲)

Exception: 分为两种,一种是RunTimeException ,也叫unchecked异常比如数字越界,空指针,等都是运行时异常,调用可以try cath 或者什么都不做(默认是往外层)。

                                       一种是checked异常,这类异常抛出去以后,调用着必须try ,catch 或者往外抛。数据库连接异常以及典型的IO异常,ClassNotFound都属于这类异常

最直接的表现形式在代码上是如下:

  1. public class ME {  
       public static void main(String[] args){  
           //当程序执行过程中,遇到uncheck exception,则程序中止,不再执行之后的代码。  
           test1();   
           test2();    
             
           try {  
               test3();  
           } catch (Exception e) {  
               throw new RuntimeException(e);  
           }  
           try {
    test4();
    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
       }  
         
       //运行时异常:方法内部抛出的异常,则throw即可,调用者可捕获也可不捕获。

       public static  void test1(){  
           System.out.println("invoke test1");  
           throw new IllegalArgumentException();    
       }  
       //uncheck exception,调用时候不需要捕获  ,声明throws即可,调用者可捕获也可不捕获
       public static  void test2() throws IllegalArgumentException{  
           System.out.println("invoke test2");  
       }  
       //check exception,调用的时候必须捕获
       public static  void test3() throws Exception{  
           System.out.println("invoke test3");  
       }  
       //check exception,调用的时候必须捕获
       public static  void test4() throws Exception  {  
           System.out.println("invoke test3");  
           throw new Exception();
       }  

    }

其实像RunTimeException 如果调用者不捕获,则会一直外抛,知道抛到main函数或者Thread.run(多线程)

何时定义RunTimeException 何时定义 Checked异常呢 ,有下面三个参考

(1) 该异常发生后是可以被恢复的,如一个Internet连接发生异常被中止后,可以重新连接再进行后续操作。

(2) 程序依赖于不可靠的外部条件,该依赖条件可能出错,如系统IO。

(3) 该异常发生后并不会导致程序处理错误,进行一些处理后可以继续后续操作。

如果调用者捕获到异常后有恢复程序的能力,则可以抛出Checked异常,让调用者明确知道你会抛出什么异常,他能采取什么措施

下面说说

 try {

   }

 catch(e1){

}

catch( e2){

}

finally {

}

这样的顺序:

e1,e2的顺序,要先子类,后父类

因为当异常产生时,JVM会按照顺序查找与异常匹配的catch块,如果把catch(Exception   e)放在所有catch块的最前面,由于大多数RuntimeException类都继承了Exception类,所有的异常都会被catch(Exception   e)所捕捉。这意味着其它的catch块都不会被执行。所以catch块的排列顺序应该是按照先子类、后父类的方式排列,最后才是catch(Exception   e) 

使用finally块释放资源

finally 最好不要抛出异常,因为在捕获到异常后,jvm会先执行fianlly里面的代码,执行完毕才回到catch里面的代码,这样如果

    finally关键字保证无论程序使用任何方式离开try块,finally中的语句都会被执行。在以下三种情况下会进入finally块:

(1) try块中的代码正常执行完毕。

(2) 在try块中抛出异常。

(3) 在try块中执行return、break、continue。

因此,当你需要一个地方来执行在任何情况下都必须执行的代码时,就可以将这些

代码放入finally块中。当你的程序中使用了外界资源,如数据库连接,文件等,必须将释放这些资源的代码写入finally块中。

必须注意的是,在finally块中不能抛出异常。JAVA异常处理机制保证无论在任何情况下必须先执行finally块然后在离开try块,因此在try块中发生异常的时候,JAVA虚拟机在执行catch()的代码后,先转到finally块执行finally块中的代码,finally块执行完毕后,再向外抛出异常。如果在finally块中抛出异常,try块捕捉的异常就不能抛出,因为被finally抛出异常覆盖了,外部捕捉到的异常就是finally块中的异常信息,而try块中发生的真正的异常堆栈信息则丢失了。(在catch里面同样可以抛出异常,但是也会覆盖掉try里面的异常,执行顺序为
try catch finally, 后面的异常会覆盖前面的异常。)

异常不能影响对象的状态(失败原子性,在practical java里面有讲到)
异常产生后不能影响对象的状态,这是异常处理中的一条重要规则。 在一个函数
中发生异常后,对象的状态应该和调用这个函数之前保持一致,以确保对象处于正确的状态中。
如果对象是不可变对象(不可变对象指调用构造函数创建后就不能改变的对象,即
    创建后没有任何方法可以改变对象的状态),那么异常发生后对象状态肯定不会改变。如果是可变对象,必须在编程中注意保证异常不会影响对象状态。有三个方法可以达到这个目的:
(1) 将可能产生异常的代码和改变对象状态的代码分开,先执行可能产生异常的代码,如果产生异常,就不执行改变对象状态的代码。
(2) 对不容易分离产生异常代码和改变对象状态代码的方法,定义一个recover方法,在异常产生后调用recover方法修复被改变的类变量,恢复方法调用前的类状态。
(3) 在方法中使用对象的拷贝,这样当异常发生后,被影响的只是拷贝,对象本身不会受到影响。

异常转换的时候,丢失异常信息

,在JDK1.4.1中,Throwable类增加了两个构造方法,public Throwable(Throwable
cause)和public Throwable(String message,Throwable cause),在构造函数中传入的原始异常堆栈信息将会在printStackTrace方法中打印出来



抱歉!评论已关闭.