介绍
异常就是阻止当前方法或者作用域继续执行的错误。java中的异常主要分为Error异常和Exception异常。两个都继承自Throwable。
Error异常主要是用来表示编译时和系统中的错误。
Exception异常指一般的可以抛出的异常,这类异常需要通过程序去捕获然后进行处理。Exception异常通常是java程序员关心的。
Java异常终止模型
Java本身支持终止模型。程序从某一个小点发生异常,那么程序将无法回调异常发生的地方继续执行。意思就是一旦异常抛出,那么就标明错误已经无法挽回了,也不能回来继续执行了。这样就需要我们对于可能发生的异常做假设。
public class Dog {
public static void main(String[] args) {
String str = null;
System.out.println(str.charAt(0));
System.out.println("123456");
}
}
结果:
1.jpg
解释:可以发现程序抛出空指针异常,然后程序终止,打印123456也执行。
Java异常捕获
前面提到了Java的终止模型,需要我们自己对可能发生的异常进行捕获。
public static void main(String[] args) throws Exception {
try {
int i = 3 / 0;
} catch (ArithmeticException e) {
throw new RuntimeException(e);
} finally {
System.out.println("123456");
}
}
2.jpg
解释:此处除数为0,然后抛出算术异常。
- Java异常链,在我们捕获异常时,想抛出一个新的异常,希望把原始异常信息保存下来,最终向上层传递,统一处理,这条链叫异常链。现在Throwable的子类都需要传递一个Throwable对象作为参数。通过这个对象将原始异常传递给新的异常,这样就可以保证虽然当前位置创建抛出新的异常,但是通过这个新的异常也可以找回原始的异常。
- finally子句作用,可以保证不管异常怎样执行,finally子句一定会执行。这样就可以保证,我们在发生异常时,依然可以关闭流等操作。
finally注意的点:
① return中使用finally:因为finally语句一定会执行,所以我们可以在方法中写多个返回。
public class Dog {
public static void eatFood(int foodType) {
try {
if (foodType == 1) {
return;
}
} finally {
System.out.println("123456");
}
}
public static void main(String[] args) throws Exception {
eatFood(1);
}
}
结果:
3.jpg
② break中使用finally:因为finally语句一定会执行,所以虽然在while语句中写finally语句,跳出循环,finally语句也会执行。
public static void main(String[] args) throws Exception {
while (true) {
try {
break;
} finally {
System.out.println("123456");
}
}
}
结果:
4.jpg
异常匹配顺序
当系统抛出异常时,系统处理异常会按照程序的顺序找出最近的处理程序。找到匹配的处理程序进行处理异常之后,就不查找了。
public static void main(String[] args) throws Exception {
try {
int i = 3 / 0 ;
String str = null;
str.charAt(0);
} catch(NullPointerException e) {
throw new RuntimeException(e);
} catch(ArithmeticException e1) {
throw new RuntimeException(e1);
}
}
5.jpg
解释:
通过例子可以发现,空指针异常虽然在代码上是距离除数为0的最近处理程序。但是却不是匹配的处理程序。并且还可以看出当抛出算术异常时,程序将终止,将不会向继续查找空指针异常。
异常丢失的BUG
当我们在finally语句中抛出了异常,那么之前捕获的异常将会被取代,编程时需注意。
public static void main(String[] args) throws Exception {
try {
int i = 3 / 0;
} catch (ArithmeticException e) {
throw new RuntimeException(e);
} finally {
String str = null;
str.charAt(0);
}
}
结果:
6.jpg
解释:可以发现finally中的空指针异常取代了之前捕获的算术异常。
Excpetion和Error的区别
Error:主要是系统出错,jvm处于非正常的状态,这点我们是无法控制的,譬如NoClassDefFoundErr。
Exception:主要分为两类,一个是可以在编译器检查出的异常,譬如:IOException、InterruptedException;还有一个是不可检查的异常,譬如:空指针异常,下标越界异常,而这类异常也可以说是运行期异常RuntimeException。
在网上找到一张图:
异常图.jpg
经典面试题
NoClassDefFoundError 和 ClassNotFoundException区别
NoClassDefFoundError抛出的原因:
JVM在使用ClassLoader来实现类加载时,在类路径上没有找到对应的class文件。而最终的原因就是在jvm运行时期,没有加载到jar包中的类.class。
ClassNotFoundException抛出的原因:
spring中配置不好会经常抛出这个错误,主要是因为spring通过类名采用反射的方式Class.forName来加载类,jvm在类路径上没有找到类名对应的类,那么就会抛出这个异常。
网友评论