异常体系层

image.png
我们的关注点可能主要在四个类上:

  • Throwable
  • Error
  • Exception
  • RuntimeException

所有的异常都是由Throwable 继承而来,但在下一层立即分解为两个分支:Error 和 Exception。Error类层次结构描述了Java运行时系统的内部错误资源耗尽错误。Exception 层次分解为两个分支: RuntimeException其他异常。

RuntimeException 异常

  • 错误的类型转换 ClassCastException
  • 数组访问越界 ArrayIndexOutOfBoundsException
  • 访问null指针 NullPointerException

    受查异常

  • 试图在文件尾部后面读取数据

  • 试图打开一个不存在的文件
  • 试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在

Java语言规范将派生于 Error 异常或 RuntimeException 类的所有异常称为非受查(unchecked) 异常。所有其他的异常称为受查(checked)异常

异常处理机制

遇到异常怎么办?要么自己想办法处理,要么就抛给别人。

捕获异常 try、catch 和 finally

  • 首先是 try-catch 语句

基本语法如下:

  1. try {
  2. // 可能会发生异常的程序代码
  3. } catch (Type1 id1){
  4. // 捕获并处置try抛出的异常类型Type1
  5. } catch (Type2 id2){
  6. //捕获并处置try抛出的异常类型Type2
  7. }

关键词 try 后面的大括号区域为可能发生异常的代码,称为监控区。当抛出异常或者出现运行时异常,然后由 Java 运行时系统巡展匹配 catch 子句。若有匹配的catch子句,则运行其异常处理代码,try-catch语句结束。
匹配规则:抛出的异常属于 catch 语句捕获异常类及子类,则匹配成功。
一旦某个catch捕获到匹配的异常类型,将进入异常处理代码。一经处理结束,就意味着整个try-catch语句结束。其他的catch子句不再有匹配和捕获异常类型的机会,并且 try 里面如果有没有走完的语句也会自动跳过

  • try-catch-finally

这个很简单,无论 try-catch 是正常结束还是发生异常捕获,都会执行 finally 语句,如果在 finally 之前发生了 return,那么 finally 语句块会在 retrun 之前执行。

  1. try {
  2. // 可能会发生异常的程序代码
  3. } catch (Type1 id1){
  4. // 捕获并处置try抛出的异常类型Type1
  5. } catch (Type2 id2){
  6. //捕获并处置try抛出的异常类型Type2
  7. }finally{
  8. //do something
  9. }

抛出异常

任何 Java 代码都可以抛出异常,语句通过 throw 抛出、方法则是 throws。
为什么要 throw 异常?
如果一个方法可能会出现异常,但是没有能力处理这种又一次,则可以在方法声明处用 throws 语句来抛出。throws 语句可以同时声明抛出多个异常,语法格式如下:

  1. void methodName()throws Exception1,Exception2,Exception3{
  2. }
  • 如果是不可查异常,那么不用声明,编译仍然可以通过,但是运行时会被JVM 抛出。
  • 如果是可查异常,要么 try-catch,要么 throws,否则编译无法通过。
  • 当抛出了异常时,该方法的调用者才会处理或者重新抛出该异常。
  • 调用 throws 异常的方法,必须 try-catch 调用语气,且 catch 的异常必须是抛出异常的同类或者父类。

Java7与异常

try-with-resources

所谓的try-with-resources,是个语法糖。实际上就是自动调用资源的close()函数。和Python里的with语句差不多。
不使用try-with-resources,我们在使用io等资源对象时,通常是这样写的:

  1. String getReadLine() throws IOException {
  2. BufferedReader br = new BufferedReader(fileReader);
  3. try {
  4. return br.readLine();
  5. } finally {
  6. if (br != null) br.close();
  7. }
  8. }

使用try-with-recources的写法:

  1. String getReadLine() throws IOException {
  2. try (BufferedReader br = new BufferedReader(fileReader)) {
  3. return br.readLine();
  4. }
  5. }

编绎器自动在try-with-resources后面增加了判断对象是否为null,如果不为null,则调用close()函数的的字节码。
只有实现了java.lang.AutoCloseable接口,或者java.io.Closable(实际上继随自java.lang.AutoCloseable)接口的对象,才会自动调用其close()函数。
**

自定义异常

  1. 定义一个派生于Exception的类,或者派生于Exception子类的类。
  2. 习惯上,定义的类应该包含两个构造器。一个默认的构造器,另一个是带有详细描述信息构造器。
    1. class FileFormatException extends IOException
    2. {
    3. public FileFormatException(){}
    4. public FileFormatException(String message)
    5. {
    6. super(message);
    7. }
    8. }