异常的基本概念

徘徊边缘 提交于 2020-03-11 18:59:02

目标:

1)异常基本概念,

2)处理异常基本格式

3)异常继承结构

4)掌握JAVA异常处理机制。

具体内容

异常:导致程序中断的一种指令流。

public class ExceptionDemo01{
    public static void main(String args[]){
        System.out.println("********** 计算开始 ***********") ;
        int i = 10 ;        // 定义整型变量
        int j = 0 ;            // 定义整型变量
        int temp = i / j ;    // 此处产生了异常
        System.out.println("两个数字相除的结果:" + temp) ;
        System.out.println("********** 计算结束 ***********") ;
    }
};

产生异常:

********** 计算开始 ***********
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at methoud.ThisDemo06.main(ThisDemo06.java:8)

处理异常

每当异常产生,会在程序中产生一个异常化的实例化对象,之后使用此对象与catch中的异常类型相互匹配,

如果匹配成功,则执行catch语句中内容,如果匹配不成功,向下继续匹配。如果都无法匹配,程序会中断执行。

异常处理格式:

package methoud;

public class ThisDemo06{
    public static void main(String args[]){
        System.out.println("********** 计算开始 ***********") ;
        int i = 10 ;        // 定义整型变量
        int j = 0 ;            // 定义整型变量
        try{
            int temp = i / j ;    // 此处产生了异常
            System.out.println("两个数字相除的结果:" + temp) ;
            System.out.println("----------------------------") ;
        }catch(ArithmeticException e){
            System.out.println("出现异常了:" + e) ;
        }
        System.out.println("********** 计算结束 ***********") ;
    }
};运行结果:

********** 计算开始 ***********
出现异常了:java.lang.ArithmeticException: / by zero
********** 计算结束 ***********

以上是基本异常处理过程,try-catch,try捕获异常,出现异常后不再执行,而是跳到catch语句执行,处理异常。

当然,异常也可以设置统一出口,使用finally语句,无论是否发生异常都会执行。

public class ExceptionDemo03{
    public static void main(String args[]){
        System.out.println("********** 计算开始 ***********") ;
        int i = 10 ;        // 定义整型变量
        int j = 0 ;            // 定义整型变量
        try{
            int temp = i / j ;    // 此处产生了异常
            System.out.println("两个数字相除的结果:" + temp) ;
            System.out.println("----------------------------") ;
        }catch(ArithmeticException e){    // 捕获算术异常
            System.out.println("出现异常了:" + e) ;
        }finally{    // 作为异常的统一出口
            System.out.println("不管是否出现异常,都执行此代码") ;
        }
        System.out.println("********** 计算结束 ***********") ;
    }
};运行结果:

********** 计算开始 ***********
出现异常了:java.lang.ArithmeticException: / by zero
不管是否出现异常,都执行此代码
********** 计算结束 ***********

以上只是处理一个异常,如果同时有多个异常呢?

修改代码,通过初始化参数,输入i和j。

package methoud;

public class ThisDemo06{
    public static void main(String args[]){
        System.out.println("********** 计算开始 ***********") ;
        int i = 0 ;        // 定义整型变量
        int j = 0 ;            // 定义整型变量
        try{
            String str1 = args[0] ;        // 接收第一个参数
            String str2 = args[1] ;        // 接收第二个参数
            i = Integer.parseInt(str1) ;    // 将第一个参数由字符串变为整型
            j = Integer.parseInt(str2) ;    // 将第二个参数由字符串变为整型
            int temp = i / j ;    // 此处产生了异常
            System.out.println("两个数字相除的结果:" + temp) ;
            System.out.println("----------------------------") ;
        }catch(ArithmeticException e){    // 捕获算术异常
            System.out.println("出现异常了:" + e) ;
        }
        System.out.println("********** 计算结束 ***********") ;
    }
};

产生异常:

********** 计算开始 ***********
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
    at methoud.ThisDemo06.main(ThisDemo06.java:9)

实际上,数据是交给用户输入的,要是用户输入不正确,可能会发生三个问题:

1)如果没有输入参数,或者参数输入不够。

2)如果现在输入的参数是字母不是数字。

3)算数异常,如果被整除的是0.

要想保证程序正确执行,需要三个异常进行处理。使用三个catch语句。

public class ExceptionDemo05{
    public static void main(String args[]){
        System.out.println("********** 计算开始 ***********") ;
        int i = 0 ;        // 定义整型变量
        int j = 0 ;            // 定义整型变量
        try{
            String str1 = args[0] ;        // 接收第一个参数
            String str2 = args[1] ;        // 接收第二个参数
            i = Integer.parseInt(str1) ;    // 将第一个参数由字符串变为整型
            j = Integer.parseInt(str2) ;    // 将第二个参数由字符串变为整型
            int temp = i / j ;    // 此处产生了异常
            System.out.println("两个数字相除的结果:" + temp) ;
            System.out.println("----------------------------") ;
        }catch(ArithmeticException e){    // 捕获算术异常
            // System.out.println("算术异常:" + e) ;
            e.printStackTrace() ;
        }catch(NumberFormatException e){    // 捕获数字转换异常
            System.out.println("数字转换异常:" + e);
        }catch(ArrayIndexOutOfBoundsException e){    // 捕获数组越界异常
            System.out.println("数组越界异常:" + e) ;
        }
        System.out.println("********** 计算结束 ***********") ;
    }
};

以上只是一个很小的程序都要处理三个异常。当然还有可能有更多异常。那么处理更麻烦。

异常类的继承结构

从之前的三个异常:ArithmeticException  NumberFormatException  ArrayIndexOutOfBoundsException 。

在整个异常结构中有两个最常用的类:Exception  Error.这两个类都是继承子throwable的子类。

 

注意:

一般输出异常信息的时候可以直接使用System.out.println(e) ;

也可以使用Exception提供的一个方法:public void printStackTrace() ;

public class ExceptionDemo06{
    public static void main(String args[]){
        System.out.println("********** 计算开始 ***********") ;
        int i = 0 ;        // 定义整型变量
        int j = 0 ;            // 定义整型变量
        try{
            String str1 = args[0] ;        // 接收第一个参数
            String str2 = args[1] ;        // 接收第二个参数
            i = Integer.parseInt(str1) ;    // 将第一个参数由字符串变为整型
            j = Integer.parseInt(str2) ;    // 将第二个参数由字符串变为整型
            int temp = i / j ;    // 此处产生了异常
            System.out.println("两个数字相除的结果:" + temp) ;
            System.out.println("----------------------------") ;
        }catch(ArithmeticException e){    // 捕获算术异常
            // System.out.println("算术异常:" + e) ;
            e.printStackTrace() ;
        }catch(NumberFormatException e){    // 捕获数字转换异常
            System.out.println("数字转换异常:" + e);
        }catch(ArrayIndexOutOfBoundsException e){    // 捕获数组越界异常
            System.out.println("数组越界异常:" + e) ;
        }catch(Exception e){
            System.out.println("其他异常:" + e) ;
        }
        System.out.println("********** 计算结束 ***********") ;
    }
};

异常处理机制

异常的处理步骤一般如下:

之前讲解过面向对象的多态性:子类的实例化对象可以直接使用父类的对象进行接收。

那么异常处理中也可以使用这种概念。因为try产生的是一个实例化对象。如果有其他不知道的异常的话,可以最后使用Exception进行捕获。

package methoud;

public class ThisDemo06{
    public static void main(String args[]){
        System.out.println("********** 计算开始 ***********") ;
        int i = 0 ;        // 定义整型变量
        int j = 0 ;            // 定义整型变量
        try{
            String str1 = args[0] ;        // 接收第一个参数
            String str2 = args[1] ;        // 接收第二个参数
            i = Integer.parseInt(str1) ;    // 将第一个参数由字符串变为整型
            j = Integer.parseInt(str2) ;    // 将第二个参数由字符串变为整型
            int temp = i / j ;    // 此处产生了异常
            System.out.println("两个数字相除的结果:" + temp) ;
            System.out.println("----------------------------") ;
        }catch(ArithmeticException e){    // 捕获算术异常
            // System.out.println("算术异常:" + e) ;
            e.printStackTrace() ;
        }catch(NumberFormatException e){    // 捕获数字转换异常
            System.out.println("数字转换异常:" + e);
        }catch(ArrayIndexOutOfBoundsException e){    // 捕获数组越界异常
            System.out.println("数组越界异常:" + e) ;
        }catch(Exception e){
            System.out.println("其他异常:" + e) ;
        }
        System.out.println("********** 计算结束 ***********") ;
    }
};

注意:捕获更粗的异常要放在捕获更细的异常前面。

因为如果放在前面会导致更细的异常捕获不到。例如下面:

package methoud;

public class ThisDemo06{
    public static void main(String args[]){
        System.out.println("********** 计算开始 ***********") ;
        int i = 0 ;        // 定义整型变量
        int j = 0 ;            // 定义整型变量
        try{
            String str1 = args[0] ;        // 接收第一个参数
            String str2 = args[1] ;        // 接收第二个参数
            i = Integer.parseInt(str1) ;    // 将第一个参数由字符串变为整型
            j = Integer.parseInt(str2) ;    // 将第二个参数由字符串变为整型
            int temp = i / j ;    // 此处产生了异常
            System.out.println("两个数字相除的结果:" + temp) ;
            System.out.println("----------------------------") ;
        }catch(Exception e){
            System.out.println("其他异常:" + e) ;
        }catch(ArithmeticException e){    // 捕获算术异常
            // System.out.println("算术异常:" + e) ;
            e.printStackTrace() ;
        }
        System.out.println("********** 计算结束 ***********") ;
    }
};

结果:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    Unreachable catch block for ArithmeticException. It is already handled by the catch block for Exception

    at methoud.ThisDemo06.main(ThisDemo06.java:18)

既然所有Exception对象都可以使用Exception接收(发生向上转型),那么直接使用Exception不是更方便吗?

package methoud;

public class ThisDemo06{
    public static void main(String args[]){
        System.out.println("********** 计算开始 ***********") ;
        int i = 0 ;        // 定义整型变量
        int j = 0 ;            // 定义整型变量
        try{
            String str1 = args[0] ;        // 接收第一个参数
            String str2 = args[1] ;        // 接收第二个参数
            i = Integer.parseInt(str1) ;    // 将第一个参数由字符串变为整型
            j = Integer.parseInt(str2) ;    // 将第二个参数由字符串变为整型
            int temp = i / j ;    // 此处产生了异常
            System.out.println("两个数字相除的结果:" + temp) ;
            System.out.println("----------------------------") ;
        }catch(Exception e){
            System.out.println("其他异常:" + e) ;
        }
        System.out.println("********** 计算结束 ***********") ;
    }
};运行结果:

********** 计算开始 ***********
其他异常:java.lang.ArrayIndexOutOfBoundsException: 0
********** 计算结束 ***********

当所有的异常处理方式一致的时候就可以使用上诉方式。直接Exception进行捕获。当然开发中不建议,最好分别捕获。

问题:

既然Exception可以,那么直接Throwable可以吗?

首先这种做法是可以的,但开发人员一般不会这么做,因为程序中,try永远之后抛出Exception错误,而Throwable还有Error。

总结

1)异常出现后,如果没有合理的处理的话,则会让整个程序中断执行。

2)每当异常产生,会在程序中产生一个异常化的实例化对象,之后使用此对象与catch中的异常类型相互匹配,

如果匹配成功,则执行catch语句中内容,如果匹配不成功,向下继续匹配。如果都无法匹配,程序会中断执行。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!