程序在运行过程中会因为很多原因导致程序出错,我们可以把可能会出现的错误用异常来表示,良好的try…catch会使我们的程序更加的健壮,所以优秀的代码离不开异常的处理
一丶异常的概念
在java中把导致程序中断运行的情况分为两种,一种就是异常,而另外一种叫做错误。所有异常的基类是Exception,错误的基类是Error。Exception是在java程序中可以编码进行控制的,具有可编程性,而Error是指Java运行时系统来显示与运行时系统本身有关的错误,Error对于程序员来说是灾难性的,程序无法控制,比如jvm堆栈溢出错误,操作系统分配内存错误等。不管是Exception还是Error,他们的共同父类是java.lang.Throwable(可抛出的) 类。
异常是指在程序运行期可能出现的非正常情况,这些情况将导致程序出错,这种出错不同于代码编写错误或程序算法出错,代码编写错误无法完成编译,而程序算法出错计算将取得错误的结果。程序出现异常时,缺省会直接造成程序的中断运行,提前预知这种异常的可能性可以补充异常处理的逻辑,从这个角度出发,异常也是一种行之有效的逻辑处理机制,在程序中声明异常或主动抛出异常也很常见。
简而言之,为了提高程序的健壮性,异常需要由程序员处理。
二丶异常的分类
1.Throwable
可抛出的,是异常的顶层父类,其他的异常或者错误都是Throwable的子类类型,只有是Throwable的体系类型,才可以使用异常的处理机制。
2.Error
称为错误,由JAVA虚拟机生成并抛出,包括动态链接失败、虚拟机异常等;程序对其不作处理
3.Exception
- 运行时异常: 都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
- 非运行时异常:是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
三丶异常的处理格式和方法
1 try{
2 //可能出现异常的代码
3 }catch(可能出现异常的类型1 标识符){
4 //针对该异常的处理方式1
5 }catch(可能出现异常的类型2 标识符){
6 //针对该异常的处理方式2
7 }finally{
8 //最终执行的代码块
9 }
View Code
常用方法:
1、Throwable中的构造方法
Throwable():创建一个没有任何参数的异常对象
Throwable(String mes):创建一个带有指定消息的异常对象
Throwable(Throwable cause):创建一个有原因的异常对象
2、常用成员方法
getCause():获取异常对象中的原因异常
getMessage():获取异常详细的消息字符串
toString():返回此throwable的简短描述
printStackTrace():打印异常的调用栈轨迹
四丶异常的捕获和处理
1、try{}catch{}捕捉异常
public class Test {
public static void main(String[] args) {
try{
//可能会出现问题的程序
int a [] = new int[5];
a[10] = 10;
}catch (ArrayIndexOutOfBoundsException e){
//异常发生时的处理语句
System.out.println("超出数组范围!");
}finally {
//这个代码块一定会被执行
System.out.println("*****");
}
System.out.println("异常处理结束!");
}
}
View Code
可以看出,在异常捕捉的过程中要进行两个判断,第一是try程序块是否有异常产生,第二是产生的异常是否和catch()括号内想要捕捉的异常相同。
那么,如果出现的异常和catch()内想要捕捉的异常不相同时怎么办呢?事实上我们可以在一个try语句后跟上多个异常处理catch语句,来处理多种不同类型的异常。
1 public class Test {
2 public static void main(String[] args) {
3 try {
4 //要检查的程序语句
5 int a[] = new int[5];
6 a[0] = 3;
7 a[1] = 0;
8 //a[1] = 0;//除数为0异常
9 //a[10] = 7;//数组下标越界异常
10 int result = a[0]/a[1];
11 System.out.println(result);
12 } catch(ArrayIndexOutOfBoundsException ex) {
13 //异常发生时的处理语句
14 System.out.println("数组越界异常");
15 ex.printStackTrace();
16 } catch(ArithmeticException ex) {
17 System.out.println("算术运算异常");
18 //显示异常的堆栈跟踪信息
19 ex.printStackTrace();
20 } finally {
21 //这个代码块一定会被执行
22 System.out.println("finally语句不论是否有异常都会被执行。");
23 }
24 System.out.println("异常处理结束!");
25 }
26 }
View Code
上述例子中ex.printStackTrace();就是对异常类对象ex的使用,输出了详细的异常堆栈跟踪信息,包括异常的类型,异常发生在哪个包、哪个类、哪个方法以及异常发生的行号。
2、声明并抛出异常
throws声明的方法表示该方法不处理异常,而由系统自动将所捕获的异常信息抛给上级调用方法。
1 public class Test {
2 public static void main(String[] args) {
3 int[] a = new int[5];
4 try {
5 setZero(a,10);
6 } catch(ArrayIndexOutOfBoundsException ex) {
7 System.out.println("数组越界错误!");
8 System.out.println("异常:"+ex);
9 }
10 System.out.println("main()方法结束。");
11 }
12 private static void setZero(int[] a,int index) throws ArrayIndexOutOfBoundsException {
13 a[index] = 0;
14 }
15 }
View Code
3、自定义异常
throw的作用是手工抛出异常类的实例化,对象throw通常和throws联合使用,抛出的是程序中已经产生的异常类实例。
1 public class Test {
2 public static void main(String[] args) {
3
4 try{
5 Test test = new Test();
6 test.regist(-100);
7
8 }catch(MyException e){
9 System.out.println("异常:"+e);
10 e.printStackTrace();
11 }finally {
12 System.out.println("结束");
13 }
14 }
15
16 public void regist(int num)throws MyException{
17 if(num<0){
18 throw new MyException("人数为负值,不合理");
19 }
20 System.out.println("登记人数:"+num);
21 }
22 }
View Code
五丶异常处理总结
养成良好的编程习惯,不要把错误给吞噬掉(即捕获到异常以后又不做出相应处理的做法,这种做法相当于是把错误隐藏起来了,可实际上错误依然还是存在的), 也不要轻易地往外抛错误,能处理的一定要处理,不能处理的一定要往外抛。往外抛的方法有两种,一种是在知道异常的类型以后,方法声明时使用throws把 异常往外抛,另一种是手动往外抛,使用“throw+异常对象”你相当于是把这个异常对象抛出去了,然后在方法的声明写上要抛的那种异常。