在 Java 中,所有的异常的都继承了java.lang
中的Throwable
类,其主要有两个子类:
Exception
:异常Error
:错误
Exception
Exception
是程序本身可以处理的异常,可以通过catch
语句捕获处理。主要分为两种:
- Checked Exception:检查异常
- Unchecked Exception:不检查异常
检查异常
Checked Exception 必须被try-catch
或者throws
处理,如果没有处理则无法通过编译。
除了RuntimeException
及其子类以外,其他的Exception
及其子类都属于受检查异常,例如IOException
、SQLException
。
不检查异常
Unchecked Exception 又被称为运行时异常,即使不处理它也可以通过编译。RuntimeException
及其子类都为不受检查异常,常见的有:
ArithmeticException
:算术错误NullPointerException
:空指针错误ClassCastException
:类型转换错误SecurityException
:安全错误比如权限不够ArrayIndexOutOfBoundsException
:数组越界错误IllegalArgumentException
:参数错误比如方法入参类型错误UnsupportedOperationException
:不支持的操作错误比如重复创建同一用户NumberFormatException
:字符串转换为数字格式错误,是IllegalArgumentException
的子类
例如NullPointerException
,即使没有用try-catch
语句捕获它或throws
子句声明抛出它,也会编译通过。
异常处理
遇到异常时往往需要先抛出,然后捕获处理。
抛出
当一个方法出现错误引发异常时,方法创建异常对象并交付运行时系统,异常对象中包含了异常类型和异常出现时的程序状态等异常信息,运行时系统负责寻找处置异常的代码并执行,java 中使用throws
抛出异常。
捕获
捕获及处理异常通常使用try-catch-finally
。其中,try
负责捕获异常,catch
用于处理捕获的异常,而无论是否捕获或处理异常,finally
的语句都会被执行。finally
语句执行情况如下:
- 当在
try
或catch
中遇到return
语句时,finally
的语句将在方法返回之前被执行。 - 当
try
语句和finally
语句中都有return
语句时,try
语句中的return
返回值会先被暂存在一个本地变量中,当执行到finally
语句中的return
之后,这个本地变量的值就变为了finally
语句中的return
返回值。 - 两种情况下,
finally
中的语句不会执行:- 程序所在线程死亡。
- 关闭 CPU。
注意事项
- 抛出的异常信息一定要有意义。
- 使用日志打印异常之后就不需要再抛出异常,两者不应该同时存在一段代码逻辑中。
- 不要把异常定义为静态变量,因为这样会导致异常栈信息错乱。每次手动抛出异常,我们都需要手动
new
一个异常对象抛出。 - 建议抛出更加具体的异常:比如字符串转换为数字格式错误的时候应该抛出
NumberFormatException
而不是其父类IllegalArgumentException
。
Error
Error 属于程序无法处理的错误,例如OutOfMemoryError
、StackOverflowError
等。这些错误发生时,JVM 会选择线程终止。错误是不可查的,所以不建议也不应该捕获它。
关于OutOfMemoryError
和StackOverflowError
,可以参考:Java 内存泄漏和内存溢出。