1. 异常继承关系
从图中可以看出,Throwable
是所有异常的根,异常分为如下两大类:
Error
,比较严重的异常,程序一般对此无力,比如:OutOfMemoryError
:内存耗尽。StackOverflowError
:栈溢出。
Exception
,是运行时错误,可以被捕获并处理,Exception
分为如下两类:RuntimeException及其子类
:通常是逻辑代码编程不对造成的,例如NullPointerException
,IndexOutOfBoundsException
等。非RuntimeException及其子类
:通常属于逻辑代码的一部分,例如IOException
,FileNotFoundException
等。
因此,在Java中产生逻辑代码一部分的异常时必须要抛出并捕获。故异常根据是否必须捕获又分为两类:
- 必须捕获的异常,称为
Checked Exception
,包括非RuntimeException及其子类
,但不为Error
及其子类。 - 不需要捕获的异常,
RuntimeException及其子类
和Error及其子类
。
注意:编译器对RuntimeException及其子类不做强制捕获要求,不是指应用程序本身不应该捕获并处理RuntimeException。是否需要捕获,具体问题具体分析。
2. 异常抛出
-
调用
printStackTrace
可以打印异常栈,对于调试非常有帮助。 -
若一个异常在捕获后需要抛出,则应在
new
异常对象中传入之前的异常参数,如下:public class Main { public static void main(String[] args) { try { process1(); } catch (Exception e) { e.printStackTrace(); } } static void process1() { try { process2(); } catch (NullPointerException e) { throw new IllegalArgumentException(); // 此处不加参数e } } static void process2() { throw new NullPointerException(); } }
打印如下:
java.lang.IllegalArgumentException at com.itranswarp.learnjava.Demo.process1(Demo.java:16) at com.itranswarp.learnjava.Demo.main(Demo.java:6)
可见,
NullPointerException
异常丢失了!调试代码时,最好需要打印完整的异常栈来及时发现 “根BUG案发现场” ,所以在
catch
中抛出新的异常时,需要保留传入原先异常对象,代码如下:public class Main { public static void main(String[] args) { try { process1(); } catch (Exception e) { e.printStackTrace(); } } static void process1() { try { process2(); } catch (NullPointerException e) { throw new IllegalArgumentException(e); // 此处加参数e } } static void process2() { throw new NullPointerException(); } }
打印如下:
java.lang.IllegalArgumentException: java.lang.NullPointerException at com.itranswarp.learnjava.Demo.process1(Demo.java:16) at com.itranswarp.learnjava.Demo.main(Demo.java:6) Caused by: java.lang.NullPointerException at com.itranswarp.learnjava.Demo.process2(Demo.java:21) at com.itranswarp.learnjava.Demo.process1(Demo.java:14) ... 1 more
OK~