Exception

来源:互联网 发布:java jdk是什么 编辑:程序博客网 时间:2024/05/22 00:53
异常的概念: 
1.是java提供的同于处理程序中错误的一种机制
2.所谓的错误是程序运行过程中发生的一些异常事件(如:除0,数组下标越界,所要读取的文件不存在
3.设计良好的程序应该在异常发生时提供处理这些错误的方法,使得程序不会因为这些异常发生阻断或者产生不可预知的结果
4.java程序执行的过程中如出现异常事件,可以产生一个异常类对象,该异常对象封装了异常事件的信息并将该信息
提交给java运行时系统,这个过程称为抛出异常(throw)
5.当java运行系统接收到异常对象的时候,会寻找能处理这一异常的代码并将当前的异常对象交给其处理,这一过程称为捕获异常(catch)

Java异常的始祖是Throwable,它有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。这两个类继承了类Throwable,具体可以见API文档(http://docs.oracle.com/javase/8/docs/api/index.html),上面说明的很清楚,为了更好地理解概念,下面给出了异常类层次结构图:

简单的分析上图:
Error:称为错误,由java虚拟机生成并抛出,包括动态链接失败,虚拟机错误等,程序不对其作任何处理
Exception:所有异常类的父类,其子类对应了各种各样可能出现的异常事件,一般需要用户显示的声明或者捕获
Runtime Exception:一类特殊的异常,如被0除,数组下标超过范围等,其产生比较繁琐,处理麻烦,如果显示的声明
或捕获将会对程序可读性和运行效率影响很大。因此由系统自动检测并将它们交给缺省的异常处理程序(用户可以不必对其处理)

下面不重点介绍Error,因为其是程序无法处理的错误,一般因为程序出现严重错误而导致。这个和Exception不同,它可以被程序处理的。
   
Exception 类有一个重要的子类 RuntimeException。RuntimeException 类及其子类表示“JVM 常用操作”引发的错误。例如,若试图使用空值对象引用(NullPointerException),除数为零ArithmeticException),数组越界(ArrayIndexOutOfBoundException)
 
Java的异常(包括Exception和Error)分为可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)。
可查异常(编译器要求必须处置的异常):正确的程序在运行中,很容易出现的、情理可容的异常状况。可查异常虽然是异常状况,但在一定程度上它的发生是可以预计的,而且一旦发生这种异常状况,就必须采取某种方式进行处理。
不可查异常(编译器不要求强制处置的异常):包括运行时异常(RuntimeException与其子类)和错误(Error)。
 除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。

  Exception 这种异常分两大类运行时异常和非运行时异常(编译异常)。程序中应当尽可能去处理这些异常。
运行时异常:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
非运行时异常 (编译异常):是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。


Java中是如何处理异常呢,异常先被抛出,然后被捕获。
涉及到这几个关键字:try,catch,throws,throw,finally
简单的分析这几个关键字:
try语句:
try{.....}语句指定了一段代码,该段代码就是一次捕获并处理例外的范围
在执行过程中,该段代码可能会产生并抛出一种或几种类型的异常对象,它后面的catch
语句要分别对这些异常做出相应的处理
如果没有产生例外,所有的catch代码段都被略过不执行

catch语句:
1.在catch语句块中是对异常进行处理的代码,每个try语句可以伴随一个或者多个catch语句,用于处理可能差生的
不同类型的异常对象
2.在catch中声明的异常对象(catch(someException))封装了异常事件发生的信息,在
catch语句块中可以使用这个对象的一些方法获取这些信息
3.getMessage()方法,用来得到有相关异常事件的信息;printStackTrace()方法用来跟踪异常
事件发生时执行堆栈的内容
final语句:
1.finally语句为异常处理提供一个统一的出口,使得控制流程转到
程序其他部分的以前,能够对程序的状态作统一的管理
2.无论try所指定的程序块中是否抛出例外,finally所指定额代码都要被执行
3.通常在finally语句中可以进行资源的清除的工作,比如:
关闭打开的文件;删除临时文件;.....
throws:
 如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常。
throw:
throw总是出现在函数体中,用来抛出一个Throwable类型的异常。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。

下面通过被除数为0的小程序来说明这个上面的几个关键字:

点击(此处)折叠或打开

  1. class Exception{
  2. public static void main(String[] args)
  3.      {
  4.      try
  5.      {
  6.      int a = 3;
  7.      int b = 0;

  8.      // 这块代码出现了异常
  9.      c = a / b;

  10.      // 那么异常之后的代码都不会被执行
  11.      System.out.println("Hello World");
  12.      }
  13.      catch (ArithmeticException e)
  14.      {
  15.      e.printStackTrace();
  16.      }
  17.     
  18.     }
上面我们用try{....}catch{}块捕获异常,并用ArithmeticException对象调用printStackTrace()方法用来跟踪异常事件发生时执行堆栈的内容,关于ArithmeticException异常类,详见http://docs.oracle.com/javase/8/docs/api/index.html
如果出现异常了,那么try中出现异常语句的下一条语句就不会执行,而是跳到catch语句,来处理这个异常,当然一个try语句后,可以跟多个catch语句,当我们捕获到异常,如果我们可以处理,那尽量去处理这种异常,而不是catch语句中什么操作也没有,这种编程习惯我们要摒弃,有能力处理异常一定要处理,没有能力处理则抛给它的调用者处理,而不能对这个异常不做任何处理。


点击(此处)折叠或打开

  1. class Exception{
  2. public static void main(String[] args)
  3.      {
  4.      int c = 0;
  5.      try
  6.      {
  7.      int a = 3;
  8.      int b = 0;

  9.      // 这块代码出现了异常
  10.      c = a / b;

  11.      // 那么异常之后的代码都不会被执行
  12.      System.out.println("Hello World");
  13.      }
  14.      catch (ArithmeticException e)
  15.      {
  16.      e.printStackTrace();
  17.      }
  18.      finally
  19.      {
  20.      //不管有没有发生异常,finally语句块都会被执行
  21.      System.out.println("检查程序异常");
  22.      }

  23.      System.out.println(c);
  24.      // 当b为0时,有异常,输出为c的初始值0
  25.      }
  26.     }
上面语句添加了finally语句,不管程序是否出现异常,那么finally语句都会被执行,当然关于finally的好处上文已经给出,该处为示例。

如果用finally语句,上面的写法一定是最好的么?修改上面的代码,如下图:

点击(此处)折叠或打开

  1. class ExceptionTest{
  2.     
  3.     
  4.      public static void main(String[] args){
  5.          
  6.          try{
  7.              
  8.          try{
  9.              int a =3;
  10.              int b =0;
  11.              int c = a/b;
  12.          }finally{
  13.              
  14.             System.out.println("检查异常");
  15.          }
  16.   }catch (ArithmeticException e) {
  17.              
  18.             e.printStackTrace();
  19.          }
  20.      }
  21. }

运用try/finally,try/catch语句,是不是使上面代码看起来更清晰呢?内层的try/finally语句职责是为了关闭打开文件,删除临时文件,关闭与数据库的连接,而外层try/catch语句,是为了检查异常带来的错误。上面代码如果没有异常发生,则只会打印finally语句中的执行内容。但是上面的写法并不一定不带来一些问题,比如try语句的返回值会被finally语句的返回值覆盖等。



点击(此处)折叠或打开

  1. class ExceptionTest{
  2.  public void f() throws ArithmeticException{
  3.          
  4.         int a =3;
  5.         int b = 0;
  6.         int c = a/b;
  7.         //System.out.println(c);
  8.     throw new ArithmeticException();
  9.         
  10.     } 
  11.      
  12.      public void m() throws Exception{
  13.          
  14.          f();
  15.          throw new Exception();
  16.      }
  17.      
  18.      public void n() throws Exception{
  19.          
  20.          m();
  21.          throw new Exception();
  22.      }
  23.    
  24.     public static void main(String[] args) throws Exception{
  25.         
  26.      
  27.         ExceptionTest w = new ExceptionTest();
  28.         try{
  29.         w.n();
  30.         
  31.         }catch(ArithmeticException e){
  32.             
  33.             e.printStackTrace();
  34.         }
  35.      }
  36. }
上面函数中出现异常,一层一层的抛出,最终由主函数来处理,这种不是很好的理想的处理方式。当然我们希望这样来处理:


点击(此处)折叠或打开

  1. class ExceptionTest{
  2.  public void f() throws ArithmeticException{
  3.          
  4.         int a =3;
  5.         int b = 0;
  6.         int c = a/b;
  7.         //System.out.println(c);
  8.     throw new ArithmeticException();
  9.         
  10.     } 
  11.   
  12.     public static void main(String[] args){
  13.         
  14.      
  15.         ExceptionTest w = new ExceptionTest();
  16.         try{
  17.         w.f();
  18.         
  19.         }catch(ArithmeticException e){
  20.             
  21.             e.printStackTrace();
  22.         }
  23.      }
  24. }


如何自定义异常类呢?
1.通过继承java.lang.Exception声明自己的异常类或者其他的异常类(如果继承的是RuntimeException的话,可以不捕获)
2.在方法适当的位置生成自定义的实例,并用throw语句抛出
3.在方法的声明部分用throws语句声明该方法可能抛出的异常
上面可以通过继承ArithmeticException,来重写其中的方法,来自定义类,读者可以查阅API来尝试该步操作。


下面谈一下,如果一个类继承了一个出现异常类,那么如何重写其中的方法呢?
谨记这一条:重写方法需要抛出与原方法所抛出异常类型一致异常或者不抛出异常
class A{
public void method() throws IOException{.....}
}
class B1 extends A{   //错误
public void method() throws FileNoFoundException{....}
}
class B2 extends A{   //错误
public void method() throws Exception(){......}
}
class B3 extends A{  //正确
public void method(){...}
}
class B4 extends A{ //错误
public void method() throws IOException,MyException{....}
class B5 extends A{ //正确
public void method()throws IOException{.....}
}


点击(此处)折叠或打开

  1. class ExceptionTest{

  2.      public void f() throws ArithmeticException{
  3.          
  4.         int a =3;
  5.         int b = 0;
  6.         int c = a/b;
  7.         //System.out.println(c)
  8.     throw new ArithmeticException();
  9.         
  10.     } 
  11.      
  12. }

  13. public class Exception1 extends ExceptionTest{
  14.     
  15.     public void f(){
  16.         
  17.         System.out.println("wang");
  18.     }
  19.     
  20.     public static void main(String[] args){
  21.         
  22.         Exception1 w = new Exception1();
  23.         w.f();
  24.     }
  25. }
上面完全正常,读者感兴趣可以完成其他的操作,这里不赘述。

上面文章简单的介绍Java异常,如有错误之处,请指正,谢谢!
0 0
原创粉丝点击