简单生活 趣味人生
  最后的告别 最后一个心愿是学会高飞

Java中的异常

前两天粗浅的学习了java中的反射和注释。今天再粗浅的学习下java中的异常。

在java程序中,经常可以见到如下形式的语句。

try{

   //捕获可能的异常

}catch(异常类  异常对象){

    //异常处理语句

}[finally{

   //一定会执行到的程序代码

}]

流程图如下所示。

其中finally中的语句是一定会执行到的。一般在此处进行各种输入输出流的关闭操作。

 

下面的demo展示一个简单的异常捕获

           int  a = 1;
             int  b = 0;
             try {
                 System.out.println(a/b);
          System.out.println("java"); }
catch (java.lang.ArithmeticException e) { // TODO: handle exception System.out.println(e); }

我们都知道,除数不能为0。在java中如何除数为0,则抛出 java.lang.ArithmeticException 异常,在catch中捕获这个异常并输出

输出结果:      zerojava.lang.ArithmeticException: / by zero         //除数为0

 

注:一般在输出异常的时候可直接输出 System.out.println(e); 也可使用Exception中提供的方法,e.printStackTrace();

以上的代码就是简单的try{}catch(){}异常处理结构,当在try中捕获异常后,产生异常后的代码将不会再执行,而是跳转到相应的cath语句中,用于处理异常。

 

异常类的继承结构:

在整个java的异常处理结构中,有如下两个最常用的类Exception 和Error 这两个类实际上都是Throwable的子类。

Exception:

1.可以是可被控制(checked) 或不可控制的(unchecked) 

2.表示一个由程序员导致的错误 

3.应该在应用程序级被处理

 

Error:

1.总是不可控制的(unchecked) 

2.经常用来用于表示系统错误或低层资源的错误 

3.如何可能的话,应该在系统级被捕捉

 

因此现在我们只专注于Exception。java中的所有异常都是继承自Exception类的,都是Exception的子类。

如下图所示:

上图中红色框中所有的异常都是Exception的直接子类。

实际上在异常的处理结构中,也是按照面向对象的方式进行处理的,处理的步骤如下:

1、一旦产生异常,则会产生一个异常类的实例化对象

2、在try语句中对此异常对象进行捕获

3、产生的异常对象与catch中的各个类型相匹配,匹配成功,则执行catch中的语句。

 

由于java有多态性,因此子类的对象可以使用父类的对象直接接收,在异常处理中同样适用。因此实际上

只需要在catch的时候 catch(Exception e) ,由于Exception是所有异常的父类,因此必然能捕获到所有异常。(向上转型)

当然在比较细致的程序中,是不建议这样捕获异常的,所有的异常最好分别捕获。

 

另外在捕获异常的时候,只能先捕获异常子类的异常,才能捕获其异常父类的异常。

 

 

throws与throw关键字

1、throws

在定义一个方法的时候可以使用throws关键字声明,使用throws声明的方法,表明此方法不处理异常,而交给方法的调用者去处理异常。

那么如果在main方法上使用throws抛出异常,交给谁处理呢。答案是JVM。由JVM来处理所有异常。

2、throw

不但可以由程序抛出异常,也可以人为的抛出一个异常,throw关键字的作用就是在程序中抛出一个异常,抛出的时候抛出的是一个异常类的实例化对象。

             try{
                 throw new Exception("自己抛着玩的");
             }catch(Exception e){
                 System.out.println(e);
             }

输出结果:     java.lang.Exception: 自己抛着玩的

 

区别:

1、throws出现在方法函数头;而throw出现在函数体。
2、throws表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一定抛出了某种异常。
3、两者都是消极处理异常的方式(这里的消极并不是说这种方式不好),只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。

 

在java面试中经常有人问到Exception和RuntimeException有什么区别:

 

Exception: (检查型)在程序中必须使用 异常处理块

RuntimeException :(非 检查型)可以不使用 异常处理块,如果有异常产生,将由 JVM 进行处理。

 

常见的RuntimeException:

    ClassCastException

    NullPointerException

    ArrayIndexOutOfBoundsException

    IllegalArgumentException

    NumberFormatException

 

 

自定义异常类,只需要继承Exception或者继承Exception的子类就可以完成自定义异常类。

Java中提供的都是标准的异常类,有时候需要使用自定义的异常类。

@SuppressWarnings("serial")
class MyException extends Exception{    //一个简单的自定义异常类
    public MyException(String msg){
        super(msg);
    }
}

public class Test{             
     public static void main(String[] args)  throws Exception{         
             try{
                 throw new MyException("自己抛着玩的");
             }catch(Exception e){
                 System.out.println(e);
             }             
     }
}    

 

 

注:

在catch语句中可以抛出一个异常,这样做的目的是改变异常的类型。

如果开发了一个供其他程序员使用的子系统,那么,用于表示子系统故障的异常类型可能会产生多种解释。ServletException就是这样一个异常类型的例子。执行servlet的代码可能不想知道发生错误的细节原因,但希望明确知道servlet是否有问题。

下面给出捕获异常并再次将它抛出的基本方法。

             try{
                 //access the database
             }catch(SQLException e){
                 throw new ServletException("database error" + e.getMessage());
             }    

不过还有一种更好的处理方法。可以从包装的异常,重新获得原异常

示例代码如下。

class MyException extends Exception{    //一个简单的自定义异常类
    public MyException(){}    
    public MyException(String msg){
        super(msg);
    }
}

public class Test{             
     public static void main(String[] args)  {                           
             try {
                 test();
            } catch (Throwable e) {
                // TODO: handle exception
                Throwable se = e.getCause();         //获得原异常                 
                System.out.println(se);
                System.out.println(e.getMessage());
            }
     }
     
     public static  void test() throws Throwable{
             try{
                 //access the database
                 throw new MyException("抛着玩的");
             }catch(MyException e){
                 // 对异常进行包装
                 Throwable es = new Exception("database error: " + e.getMessage());
                 es.initCause(e);
                 throw es;
             }    
     }
}

建议使用这种包装技术,这样可以抛出高级异常,而不会丢失原始异常的细节。

 

今天关于异常的学习就到这了,在实际的开发中,肯定会遇到而各种各样的问题,因此需要考虑到所有情况,才能保证程序的健壮性。

 

posted @ 2015-01-21 18:24  MayDayIT  阅读(190)  评论(0编辑  收藏  举报