异常与异常的处理

一、     异常概述:

  异常指的是程序在运行时产生的问题,在java中,把异常信息封装成一个类,出现问题的时候会创建异常类对象,将问题的详细信息封装在对象中并且抛出。我们可以根据这些信息判断问题产生的原因,位置。从而修改代码。

异常的继承体系:

  根据此图我们可以看出:

     Throwable 类是 Java 语言中所有错误或异常的超类,他有2大子类:Error 和 Exception

Error: (JVM层次的问题,程序员无法处理) 

  表示由JVM所侦测到的无法预期的错误,由于这是属于JVM层次的严重错误,导致JVM无法继续执行,因此,这是不可捕捉到的,无法采取任何恢复的操作,顶多只能显示错误信息。Error类体系描述了Java运行系统中的内部错误以及资源耗尽的情形。应用程序不应该抛出这种类型的对象(一般是由虚拟机抛出).假如出现这种错误,除了尽力使程序安全退出外,在其他方面是无能为力的。

Exception:(程序员可以处理的问题,一般需要显示地声明或捕获)

  所有异常的父类,其子类对应了各种各样可能出现的异常事件,一般需要显示地声明或捕获。Exception中包含2个子类:runtime exceptionchecked exception。

 

 

checked exception:( 必须要对其进行处理,否则无法通过编译)

  Java 中凡是继承自 Exception,而不继承自 RuntimeException 类的异常都是非运行时异常,也叫检查时异常 :IOException 必须要对其进行处理,否则无法通过编译。

 

  这类异常的产生不是程序本身的问题,通常由外界因素造成的。 为了预防这些异常产生时,造成程序的中断或得到不正确的结果,Java  要求编写可能产生这类异常的程序代码时,一定要去做异常的处理。

 

Runtime Exception:(通过程序的健壮性来处理,不推荐使用异常处理机制来处理

Runtime Exception类是 Exception 类的子类,叫做运行时异常Java 中的所有运行时异常都会直接或者间接地继承自 RuntimeException 类。

这一类特殊的异常,如被0除、数组下标超范围等,其产生比较频繁,处理麻烦,如果显示的声明或捕获将会对程序可读性可运行效率影响很大。因此由系统自动检测

并将它们交给缺省的异常处理程序(用户可不必对其处理)。我们可以通过程序的健壮性来处理,不推荐使用异常处理机制来处理。

例如:

NullPointerException:当程序访问只有引用没有对象的成员属性或成员方法。怎么处理?

ArithmeticException:除数为 0

ClassCastException:多态时类型转换错误

ArrayIndexOutOfBoundsException:访问的元素下表超过数组长度

NumberFormatException:数字格式异常

 

二、      异常产生

之所以出现异常,是因为内部抛出了异常对象,这个异常对象的产生分为系统内部产生,或程序员手动抛出异常。

  • 系统内部产生

 

 1 //工具类
 2 class ArrayTools{
 3 //对给定的数组通过给定的角标获取元素。
 4 public static int getElement(int[] arr,int index)    {
 5         int element = arr[index];
 6         return element;
 7 }
 8 }
 9 //测试类
10 class ExceptionDemo2 {
11     public static void main(String[] args)     {
12         int[] arr = {34,12,67};
13         int num = ArrayTools.getElement(arr,4)
14         System.out.println("num="+num);
15         System.out.println("over");
16     }
17 }

 

  • 程序员手动抛出

 

 1 public class ExceptionDemo {
 2     
 3 public static void main(String[] args) {
 4         
 5         int arr[] = null;
 6         try{
 7             getElement(arr, 5);
 8         }catch(ArrayIndexOutOfBoundsException e){
 9             System.out.println(e+"www");
10         }catch (RuntimeException exception) { //越大的父类越往下放 不然抓不到
11             System.out.println("RuntimeException"+exception);
12         }finally {
13             arr = null;
14         }
15         
16     }
17     /*
18      * 通过给定的数组,返回给定的索引对应的元素值。
19      */
20     public static int getElement (int[] arr, int idx) throws RuntimeException{//在方法声明处抛出异常
21         if(arr == null){
22             throw new NullPointerException("数组为null");
23         }
24         if(idx < 0 || idx >= arr.length){
25             throw new ArrayIndexOutOfBoundsException("错误的索引 :" + idx);
26         }
27         
28         int ele = arr[idx];
29         return ele;
30         
31     }
32 }

 

 

三、      异常处理和捕获

对于编译(非运行)时异常( checked exception ),必须要对其进行处理,否则无法通过编译。处理方式有两种:

1 、异常捕获 try  catch  finally

1 try {
2     //需要被检测的语句。
3 }
4 catch(异常类 变量) { //参数。
5     //异常的处理语句。
6 }
7 finally {
8     //一定会被执行的语句。
9 }

说明:

try代码段包含可能产生例外的代码

try代码段后跟有一个或多个catch代码段

每个catch代码段声明其能处理的一种特定类型的异常并提供处理的方法

当异常发生时,程序会中止当前的流程,根据获取异常的类型去执行相应的catch代码段

一个 try 后面可以跟多个 catch,但不管多少个, 最多只会有一个catch块被执行

finally段的代码无论是否发生异常都有执行

try语句

try{…}语句制定了一段代码,该段代码就是一次捕获并处理意外的范围。

在执行过程中,该段代码可能会产生并抛出一种或几种类型的异常对象,它后面的catch语句要分别对这些异常做相应的处理。

如果没有意外产生,所有的catch代码段都被略过不执行。

catch语句

catch语句块中是对异常进行处理的代码,每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。

catch中声明的异常对象封装了异常事件发生的信息,在catch语句块中可以使用这个对象的一些方法获取这些信息

  例如:

getMessage()方法,用来得到有关异常事件的信息

printStackTrace()方法,用来跟踪异常事件发生时执行堆栈的内容

finally语句

finally语句为异常处理提供一个统一的出口,使得在控制流程转到程序的其它部分以前,能够对程序的状态作统一的管理。

无论try所制定的程序块中是否抛出异常,finally所指定的代码都要被执行。

通常在finally语句中可以进行资源的清除工作,如:

关闭打开的文件

删除临时文件

2 向外 声明( 抛出) 异常  throws


  在产生异常的方法声明后面写上 throws  某一个 Exception  类型,如 throws Exception,将异常抛出到外面一层去

 1     /*
 2     如果定义功能时有问题发生需要报告给调用者。可以通过在方法上使用throws关键字进行声明。
 3     */
 4     public void show(int x)throws Exception    {
 5         if(x>0){
 6             throw new Exception();
 7         } else {
 8             System.out.println("show run");
 9          }
10     }
11 }

 

 

异常与重写

 

  •     子类覆盖父类方法时,如果父类的方法声明异常,子类只能声明父类异常或者该异常的子类,或者不声明。
1 class Fu {
2     public void method () throws RuntimeException {
3   }
4 }
5 class Zi extends Fu {
6     public void method() throws RuntimeException { }  //抛出父类一样的异常
7     //public void method() throws NullPointerException{ } //抛出父类子异常
8 }

 

  •                   当父类方法声明多个异常时,子类覆盖时只能声明多个异常的子集。
 1 class Fu {
 2 
 3     public void method () throws NullPointerException, ClassCastException{
 4 
 5   }
 6 
 7 }
 8 
 9 class Zi extends Fu {
10 
11     public void method()throws NullPointerException, ClassCastException { }      
    public void method() throws NullPointerException{ } //抛出父类异常中的一部分 12 13 public void method() throws ClassCastException { } //抛出父类异常中的一部分 14 15 }

 

  • 当被覆盖的方法没有异常声明时,子类覆盖时无法声明异常的。
 1 class Fu {
 2 
 3     public void method (){
 4 
 5     }
 6 
 7 }
 8 
 9 class Zi extends Fu {
10 
11     public void method() throws Exception { }//错误的方式
12 
13 }

 

举例:父类中会存在下列这种情况,接口也有这种情况

              问题:接口中没有声明异常,而实现的子类覆盖方法时发生了异常,怎么办?

答:无法进行throws声明,只能catch的捕获。万一问题处理不了呢?catch中继续throw抛出,但是只能将异常转换成RuntimeException子类抛出。

interface Inter {

    public abstract void method();

}

class Zi implements Inter {

    public void method(){ //无法声明 throws Exception

        int[] arr = null;

        if (arr == null) {

            //只能捕获处理

            try{

throw new Exception(“哥们,你定义的数组arr是空的!”);

} catch(Exception e){

    System.out.println(“父方法中没有异常抛出,子类中不能抛出Exception异常”);

        //我们把异常对象e,采用RuntimeException异常方式抛出

        throw new RuntimeException(e);

            }

        }

    }

}        

四、      使用自定义的异常

所谓自定义异常,通常就是定义一个类,去继承 Exception 类或者它的子类。因为异常必须直接或者间接地继承自 Exception 类。通常情况下,会直接继承自 Exception 类,一般不会继承某个运行时的异常类。

 1 class MyException extends Exception{
 2     /*
 3     为什么要定义构造函数,因为看到Java中的异常描述类中有提供对异常对象的初始化方法。
 4     */
 5     public MyException(){
 6         super();
 7     }
 8     public MyException(String message)    {
 9         super(message);// 如果自定义异常需要异常信息,可以通过调用父类的带有字符串参数的构造函数即可。
10     }
11 }

 


使用自定义异常一般有如下步骤:

1、         通过继承java.lang.Exception类声明自己的异常类

2、         在方法适当的位置生成自定义异常的实例,并用throw语句抛出

3、         在方法声明部分用throws语句声明该方法可能抛出的异常

五、重点总结

一个图异常体系

五个关键字: try  catch  finally throws throw

先逮小的,再逮大的

异常和重写的关系

 

 

posted on 2018-02-15 15:29  萌萌手好冷  阅读(284)  评论(3编辑  收藏  举报