异常的分类如下图:

java-exception

在程序当中我们需要关注 Exception 层次结构。

Java 将异常分为两类:

  • 未检查异常:派生于 RuntimeException 和 Error 类的所有异常。
  • 已检查异常:除去未检查异常的其他异常。

遇到如下四种情况的时候会抛出异常:

  • 调用一个抛出已检查异常的方法
  • 使用 throw 语句抛出一个异常
  • 程序出现未检查异常
  • Java 虚拟机和运行时库出现的内部异常

出现前两种情况之一,则必须告诉调用这个方法的程序员有可能抛出异常。

子类覆盖了父类的一个方法,子类方法中声明的已检查异常不能超过父类方法中声明的异常范围。子类可以不抛出异常或者抛出父类异常的子类异常。

捕获异常

捕获异常需要使用 try/catch 语句块。

1
2
3
4
5
6
try {

}
catch(Exception e) {

}

如果 try 语句块中的任何代码抛出一个在 catch 子句中指定的异常,那么

  • 程序将跳过 try 语句块中的其余代码
  • 程序将执行 catch 子句中的代码

如果 try 语句块中的任何代码没有抛出任何异常,那么程序跳过 catch 子句

注意:

正常结束:如果所有步骤都正常执行,没有突然结束,则称这个语句正常结束。

突然结束:语句在正常执行完所有步骤前终止,称为突然结束。

突然结束有如下几个原因:

  • break
  • continue
  • return
  • throw 异常,包括虚拟机异常
try/catch 的执行:
  • 如果 try 块的执行正常结束,那么就不采取任何进一步操作,try 块正常结束
  • 如果 try 块执行抛出异常 V,那么:
    • 若异常 V 可以匹配到 catch 子句,那么第一个被匹配的 catch 子句会执行。如果这个匹配的 catch 块正常结束,那么 try 块也正常结束。如果这个匹配的 catch 块出于任何原因突然结束,那么 try 语句以相同的原因突然结束。
    • 若异常 V 没有匹配的 catch 子句,那么 try 语句就由于抛出值 V 而突然结束。
  • 如果 try 块执行出于任何其他原因而突然结束,那么 try 语句就出于相同的原因突然结束。

当代码抛出一个异常时,就会终止对方法剩余代码的处理,如果方法中获取了一些资源,就会引发资源回收问题,我们可以使用 finally 块来关闭资源。

1
2
3
4
5
6
7
8
9
try {

}
catch(Exception e) {

}
finally {

}
try/catch/finally 的执行:
  • 如果 try 块的执行突然结束,那么 finally 块就被执行,然后进行如下选择:
    • 如果 finally 块突然结束,那么 try 语句就正常结束
    • 如果 finally 块由于原因 S 突然结束,那么 try 语句就由于原因 S 突然结束
  • 如果 try 块抛出异常 V 突然结束,那么进行如下选择:
    • 如果能匹配到 catch 块,则执行 catch 块,并且进行如下选择:
      • 如果 catch 块正常结束,那么就执行 finally 块,然后进行如下选择:
        • 如果 finally 块正常结束,那么 try 语句就正常结束
        • 如果 finally 块由于原因 S 突然结束,那么 try 语句就由于原因 S 突然结束
      • 如果 catch 块由于原因 R 突然结束,那么 finally 块被执行,然后进行如下选择:
        • 如果 finally 块正常结束,那么 try 语句就由于原因 R 突然结束
        • 如果 finally 块由于原因 S 突然结束,那么 try 语句就由于原因 S 突然结束,并且原因 R 被丢弃
    • 如果 V 没有被任何 catch 子句匹配,那么就执行 finally 块,然后进行如下选择:
      • 如果 finally 块正常结束,那么 try 语句就由于抛出异常 V 突然结束
      • 如果 finally 块由于原因 S 突然结束,那么 try 语句就由于原因 S 突然结束,并且原因 V 被丢弃
  • 如果 try 块的执行出于任何其他原因 R 而突然结束,那么 finally 被执行,并且进行如下选择:
    • 如果 finally 块突然结束,那么 try 语句就由于原因 R 突然结束
    • 如果 finally 块由于原因 S 突然结束,那么 try 语句就由于原因 S 突然结束,并且原因 R 被丢弃

—EOF—