异常的基本概念
目标:
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语句中内容,如果匹配不成功,向下继续匹配。如果都无法匹配,程序会中断执行。