深入理解Java异常

410 阅读3分钟

简介

异常就是阻止当前方法或作用域继续执行的问题。当程序运行时出现异常时,系统会生成一个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()方法就能拿到各层的异常原因

总结

  1. 处理运行时异常时,采用逻辑合理规避同时辅助try/catch处理。
  2. 在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
  3. 尽量去处理异常,而不是简单地printStackTrace()。
  4. 尽量添加finally块去释放占用的资源。