异常处理基础
try {
// 可能产生异常的代码块
} catch (ExceptionType ex) {
// 处理异常
} catch (ExceptionType ex) {
// 处理异常
} ...
finally {
// 无论是否发生异常,必须执行的代码块
}
异常类型
所有异常类型的超类是 Throwable,该类有两个直接子类,一个是 Exception,用于表示用户代码应该捕获的异常类型,所有自定义异常都继承自这个类;一个是 Error,用于表示不能被用户代码捕获的异常,这个异常类型由运行时系统使用,指出必须被处理的错误。
未捕获异常
当一个异常产生而用户没有定义对这个异常的处理器时,则这个异常最终会被运行时系统的默认异常处理器处理,处理方式是显示描述异常的字符串,并打印异常产生点的调用桟,然后终止程序。
使用 try 和 catch
自定义异常处理器可以避免使用默认异常处理器造成程序终止。
try 块用于监视可能产生异常的代码段,catch 块用于指定异常类型及处理方式。
当 try 块中某条语句产生异常时,这条语句下面的所有语句被跳过,控制流转到 catch 块,catch 块执行完毕后,控制流转到整个 try/catch 块的下一条语句,执行该语句。
多 catch 子句
catch 子句按照顺序匹配异常类型,如果类型匹配,则处理该异常,否则跳过。
多个 catch 子句的排列顺序必须是子类在前,超类在后。因为超类可以匹配自身和所有自己子类的异常类型。如果超类在前,子类在后,则子类永不可达,此时报错。
内嵌 try
内部的 try 块产生异常如果同层级的 catch 语句无法捕获,则抛给直接相邻的上一层级的 catch 语句,直至被处理。都不匹配,则由默认异常处理器处理。
throw
throw ThrowableInstance
允许被抛出的异常对象类型必须是 Throwable 或其子类。
内建运行时异常有两个构造器,一个空构造器,另一个接收一个描述该异常的字符串作为参数的构造器。
throws
当一个方法可能产生异常而不能处理时,需要声明所有可能抛出的异常。
type name(parameterList) throws exceptionList {
// body
}
finally
不论 try/catch 块中有什么样的语句,finally 块中的语句都会执行。即使 try/catch 块中有 return 语句,在 return 语句执行前, finally 块中的语句会先执行完成。try 块至少必须紧跟一个 catch 子句或 finally 子句。
try {
} finally {
}
try {
} catch() {
}
内建异常
unchecked exceptions,不需要出现在 throws 中的异常。checked 异常必须在 throws 中出现。
unchecked 异常 | checked 异常 |
---|---|
ArithmeticException | ClassNotFoundException |
ArrayIndexOutOfBoundsException | CloneNotSupportedException |
ArrayStoreException | IllegalAccessException |
ClassCastException | InstantiationException |
EnumConstantNotPresentException | InterruptedException |
IllegalArgumentException | NoSuchFieldException |
IllegalCallerException | NoSuchMethodException |
IllegalMonitorStateException | ReflectiveOperationException |
IllegalStateException | |
IllegalThreadStateException | |
IndexOutOfBoundsException | |
LayerInstantiationException | |
NegativeArraySizeException | |
NullPointerException | |
NumberFormatException | |
SecurityException | |
StringIndexOutOfBoundsException | |
TypeNotPresentException | |
UnsupportedOperationException |
创建自己的异常类
自定义异常类需要继承 Exception,Exception 类没有定义任何方法,所有的方法都是 Throwable 类定义的。
Throwable 定义的方法 |
---|
final void addSuppressed(Throwable exc) |
Throwable fillInStackTrace() |
Throwable getCause() |
String getLocalizedMessage() |
String getMessage() |
StackTraceElement[] getStackTrace() |
final Throwable[] getSuppressed() |
Throwable initCause(Throwable causeExc) |
void printStackTrace() |
void printStackTrace(PrintStream stream) |
void printStackTrace(PrintWriter stream) |
void setStackTrace(StackTraceElement elements[]) |
String toString() |
异常链(chained exception)
当一个异常 a 产生时,捕获输出这个异常的描述信息,实质上 a 是由于潜在的异常 b 产生的。为了得到潜在的异常,可以使用异常链将异常关联。
class C {
static void a() {
NullPointerException e = new NullPointerException("a 异常");
// 关联一个潜在的异常,该方法只能使用一次
e.initCause(new ArithmeticException("b 异常"));
throw e;
}
public static void main(Strings[] args) {
try {
a();
} catch(NullPointerException e) {
System.out.println("捕获:" + e);
// getCause 方法获得关联的潜在异常
System.out.println("潜在的原因:" + e.getCause());
}
}
}
三个额外的异常特性
try/finally 块可以用于自动管理资源的请求和释放。
多 catch(multi-catch)特性可以在一个 catch 块中捕获不同类型的异常。每个多 catch 中的变量隐式是 final 类型。语法为:
try {
// 可能产生异常的代码段
} catch(ExceptionTypeA | ExceptionTypeB e) {
// 处理异常
}
final rethrow(more precise rethrow)限制了可以被重抛出的异常类型,允许的类型有以下三种:关联的 try 块抛出的、没有被先前的 catch 块处理的、类型是参数的子类或超类。并且以上三种异常为 checked exception。将异常变量声明为 final 可使用该特性。
参考
[1] Herbert Schildt, Java The Complete Reference 11th, 2019.