简介
异常就是阻止当前方法或作用域继续执行的问题。当程序运行时出现异常时,系统会生成一个Exception对象来通知程序进行相应的处理。
异常体系结构
Java将异常当做对象来处理,它的体系结构图如下。

Throwable作为所有异常类的超类,异常分为两大类,Error(错误)和Exception(异常)。
Error是程序无法控制和处理的问题,如栈溢出(StackOverFlowError)、堆溢出(OutOfMemoryError)。
Exception是用户程序可以处理的异常,其下又可以分为受检异常(IOException)、非受检异常(RuntimeException,也叫运行时异常)。
- Error,由JVM生成并抛出,与程序无关,不需要捕获或处理。
- 受检异常,在运行中很容易出现的异常,对于这类异常是可预测的,我们必须要进行处理。当程序中可能出现这类异常,要么使用try-catch进行捕获,要么使用throws子句抛出,否则无法通过编译。
- RuntimeException,运行时异常,往往是由程序逻辑错误引起。对于这类异常,我们可以在选择在程序中捕获,也可以不处理。
异常处理
Java异常处理的本质是捕获异常和抛出异常。
- try-catch-finally
用法
try{
///可能会抛出异常的代码`
}catch(Type1 id1){
//处理Type1类型异常的代码`
}catch(Type2 id2){
//处理Type2类型异常的代码`
}finally{
// 回收资源
}
try块中放置可能会发生异常的代码,当异常发生,系统会生成一个异常对象并抛出。然后异常处理机制将负责查找catch语句中与该异常类型匹配的第一个处理程序,如果找到则执行catch下的处理程序。如果未找到,JVM会抛出该异常。
finally语句块总是会被执行,它主要用来回收try中的物理资源。只有finally执行完后,才会回去执行try或catch中的return、throw。如果finally中存在return、throw,那么不会跳回,方法终止。
- throw
手动抛出异常,如
throw new Exception()
- throws
public void f() throws ClassNotFoundException,IOException{}
throws关键字常用在方法签名中,当前方法如果不知道如何处理异常,则可以将异常抛给调用者或JVM。JVM对异常的处理方式是打印堆栈信息并终止程序运行。
异常链
将底层的异常逐层往上抛出,这样每层的异常组合起来就会形成一条链。
try {
lowLevelOp();
} catch (LowLevelException le) {
throw (HighLevelException) new HighLevelException().initCause(le);
}
当程序捕获到一个异常,并选择将该异常往上层传递,这样高层的异常递归调用getCause()方法就能拿到各层的异常原因。
总结
- 处理运行时异常时,采用逻辑合理规避同时辅助try/catch处理。
- 在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常。
- 尽量去处理异常,而不是简单地printStackTrace()。
- 尽量添加finally块去释放占用的资源。