先放图。
java所有异常类,继承自java.lang.Throwable。Throwable有两个直接子类,Error类和Exception类。
- Error(错误):一般指虚拟机相关的问题,入系统崩溃、虚拟机出错、动态链接失败等。这种错误无法恢复,也不可捕获,会导致程序运行中断。例如内存溢出错误。
- Exception(异常):一般分为Checked(受检)异常和Runtime异常,所有RuntimeException类及其子类的实例被称为Runtime异常,不属于该范畴的异常则被称为CheckedException。
对Checked异常处理方法有两种:
- 当前方法知道如何处理该异常,则用try…catch块来处理该异常。
- 当前方法不知道如何处理,则在定义该方法是声明抛出该异常。
Error
当我们启动程序,结果启动失败,报错。这种情况下,大部分都是Error导致的。例如java.lang.NoClassDefFoundError等。出现这种错误,需要我们去排查自己的代码。
Exception
如上所述,异常分为受检异常和运行时异常。下面针对这两种异常,分别讨论。
CheckedException
除了RuntimeException,其他均为CheckedException。如上所述,该类异常,强制我们通过try、catch捕获或通过throws声明抛出。
如上图,如果我们不对受检异常进行处理,编译会报错。有两种方式处理异常:
- 通过try、catch语句捕获
public static void main(String[] args){
getFile();
System.out.println("运行正常结束");
}
public static void getFile(){
File file = new File("Test");
InputStream in = null;
try {
in = new FileInputStream(file);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("异常后语句");
}
如上,当出现FileNotFoundException异常时,会打印出错误堆栈信息。同时,程序会继续往下运行。
java.io.FileNotFoundException: Test (系统找不到指定的文件。)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(Unknown Source)
at com.error.TestThrow.getFile(TestThrow.java:21)
at com.error.TestThrow.main(TestThrow.java:11)
异常后语句
运行正常结束
- 通过throws抛出
我们可以在方法声明上添加throws,声明该方法可能会抛出异常,并将其交由上层,也就是调用它的方法处理。而上层也有两种选择,一种是继续往上抛,一种是通过try、catch捕获。先看直接抛出的:
public static void main(String[] args) throws FileNotFoundException{
getFile();
System.out.println("运行正常结束");
}
public static void getFile() throws FileNotFoundException{
File file = new File("Test");
InputStream in = null;
in = new FileInputStream(file);
System.out.println("异常后语句");
}
运行结果如下:
Exception in thread "main" java.io.FileNotFoundException: Test (系统找不到指定的文件。)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(Unknown Source)
at com.error.TestThrow.getFile(TestThrow.java:20)
at com.error.TestThrow.main(TestThrow.java:11)
从结果可以看出,由于异常交由上层处理,出现异常后的代码不再执行。
再看,如果上层通过try、catch捕获运行结果如何:
public static void main(String[] args){
try {
getFile();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("运行正常结束");
}
结果如下:
java.io.FileNotFoundException: Test (系统找不到指定的文件。)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(Unknown Source)
at com.error.TestThrow.getFile(TestThrow.java:25)
at com.error.TestThrow.main(TestThrow.java:12)
运行正常结束
通过上面,我们可以得出如下结论:
对于受检异常,如果通过try、catch捕获,后续代码会继续执行;如果通过throws声明抛出异常,则后续代码不再执行。如果最上层也未捕获,则交由虚拟机处理,此时会导致程序终止。
RuntimeException
该类异常,不要求任何处理。如下例:
public static void div(){
int a=3;
int b=0;
int c = a/b;
System.out.println("异常后语句");
}
运行结果如下:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.error.TestThrow.div(TestThrow.java:30)
at com.error.TestThrow.main(TestThrow.java:11)
导致程序中止。
关于throws和throw
上面提到了throws,它和throw是什么关系呢?
throw可以主动抛出特定异常,如下例:
public static void div() {
int a=3;
int b=0;
if(0==b){
throw new ArithmeticException();
}else{
int c = a/b;
}
System.out.println("异常后语句");
}
程序主动抛出ArithmeticException,结果如下:
Exception in thread "main" java.lang.ArithmeticException
at com.error.TestThrow.div(TestThrow.java:30)
at com.error.TestThrow.main(TestThrow.java:11)
那么throw还有什么用呢?实际应用中,可能碰到这种情况,单靠一个类,无法完成异常处理,但通过try、catch后,上层又无法再次捕获,此时可以在catch中通过throw主动抛出异常,交由上层处理。
总结
通过上述例子可以看出,不论是Error还是Exception,都会导致程序终止。但对于Exception,通过try、catch捕获处理后,不会导致程序终止,后续代码仍可继续执行。