异常的定义:有不寻常的事发生了,该事情发生后,原本打算接着做的事情不能再继续了,必须停下来,让其他地方的代码段处理。
异常机制的重要性:在进行一系列的操作的过程中,我们可能遇到各种各样的问题,以读文件操作举例。
如果要读一个文件,有以下步骤(括号内是可能遇到的异常):
1.打开文件。(可能所给文件名的文件根本不存在,或者不在磁盘内)
2.判断文件大小。(如果正在写文件,不知道何时写结束,无法判断文件大小)
3.分配足够的内存空间。(文件很大,不一定能拿到足够内存)
4.把文件读入内存。(读的过程网络流不稳定、服务器坏了 )
5.关闭文件。(关闭的过程服务器坏了)
这五步有时间上的依赖,每一件事情能否开始依赖于前一件事是否完成。我们希望能对可能出现的任何问题进行提前防范。
Java给我们提供了一种异常机制:try{ }catch( ){ },try后的大括号里放的是可能出现问题的代码段,即业务逻辑,catch后的小括号代表异常类型,大括号里是如果捕捉到该异常会进行什么操作。
对于读文件,我们用上异常机制,伪代码如下:
假如open file出现了异常,try内剩余代码不会被执行。
我们可以看出,异常机制最大的好处就是用try和catch清晰地分开了正常的业务逻辑代码和遇到情况时的处理代码。
下面我们来看一个简单的异常处理代码,定义一个大小为10的数组a,将a[idx]赋值为100,idx取决于我们的输入,输入的idx>9则发生异常
package exception;
import java.util.*;
public class ArrayIndex {
public static void main(String[] args) {
int [] a = new int[10];
int idx;
Scanner in = new Scanner(System.in);
idx = in.nextInt();
//Java的异常机制:将可能出现异常的代码放入try{}里
try {
a[idx] = 100;
System.out.println("hello!");
//catch的意思是捕捉,这里意思是指会捕捉括号中指定类型的异常
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("Caught");//如果输出了Caught,说明第13行没有执行
//处理完异常接着往下执行,而不会去执行try里的剩余代码
}
}
第13行是输出hello!的操作,如果输入的idx<9,输出:hello!
如果输入的idx>9,输出:Caught
如果我们将a[10]等于10写入一个f()函数,然后在main函数里直接调用f()进行处理:
public class ArrayIndex {
public static void main(String[] args) {
try {
f();//都是static,可直接调用
//函数内部若有异常,函数内部异常语句之后的不会被处理。即不会输出hello!
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("Caught");
System.out.println("main!");
}
public static void f() {
int [] a = new int[10];
a[10]=10;
System.out.println("hello!");
}
}
处理完函数的异常后,程序并不会立即终止,而是会离开该函数,回到调用程序那里接着往下执行。输出:Caught main!
拿到异常对象后,我们可以做以下三件事,写在上段代码输出Caught之后:
System.out.println(e.getMessage());//异常发生时,放在异常对象里的值是10 输出:10
System.out.println(e);//输出:java.lang.ArrayIndexOutOfBoundsException: 10 格式: 异常名字:message的值
//
//输出异常描述,以及异常函数调用轨迹(调用堆栈)
//第一行就是最内层,即发生异常的地方,由内而外展开了
e.printStackTrace();//输出结果: java.lang.ArrayIndexOutOfBoundsException: 10
// at exception.ArrayIndex.f(ArrayIndex.java:34)
// // at exception.ArrayIndex.main(ArrayIndex.java:20)
其中的e.printStackTrace();是输出异常的调用轨迹,简单来说,异常会由内向外抛出,直到被捕捉到,或者最外层也没被捕捉到,就输出异常,终止程序。
而如果拿到异常后不知该做如何处理好,可将异常再度抛出.(抛到外面,如果外面也有catch,且错误类型能匹配,也可捕捉异常),适用于需要这个层面上需要处理,但是不能做最终的处理。
有点绕,直接看代码:
package exception;
import java.util.*;
public class ArrayIndex {
public static void main(String[] args) {
try {
f();//都是static,可直接调用
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("Caught");
throw e;
}
//一旦抛出异常,有很多机制去捕捉它,但肯定回不到异常发生的地方去了,具体的处理逻辑取决于业务逻辑需要
System.out.println("main!");
}
public static void f() {
int [] a = new int[10];
a[10]=10;
System.out.println("hello!");
}
}
输出如下:
注意这里并没有输出main!原因在于在于throw e这行,抛出了异常,交由外层去处理,假如有外层,且外层也捕捉到了异常且有相应操作处理,异常也会被处理,但这里main()外层没有对异常的处理,因此会输出信息说明是在main()里发生了异常 ,然后显示异常的路径。
即一旦抛出异常,有很多机制去捕捉它,但肯定回不到异常发生的地方去了,具体的处理逻辑取决于业务逻辑需要。