zoukankan      html  css  js  c++  java
  • 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;
                 }    
         }
    }

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

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

  • 相关阅读:
    为什么解析 array_column不可用,
    Android经常使用的布局类整理(一)
    C++ Coding Standard
    Kd-Tree算法原理和开源实现代码
    2013年10月5日国庆上班前一天
    2013年10月5日
    2013年10月3日合肥归来
    国庆第二天参加室友婚礼
    国庆随笔
    2013第40周日国庆放假前一天晚上
  • 原文地址:https://www.cnblogs.com/maydayit/p/4239726.html
Copyright © 2011-2022 走看看