在前面了解可知,Java中,凡是可能抛出异常的语句或非RuntimeException(Checked Exception)需强制捕获,都可以用try ... catch捕获。把可能发生异常的语句放在try { ... }中,然后使用catch捕获对应的Exception及其子类。

当然错误的原因可能不止一种,所以可以使用多个catch语句,每个catch分别捕获对应的Exception及其子类。JVM在捕获到异常后,会从上到下匹配catch语句,匹配到某个catch后,执行catch代码块,然后不再继续匹配。多个catch只有匹配的哪一个能被执行。例如

public static void main(String[] args) {
    try {
        process1();
        process2();
        process3();
    } catch (IOException e) {
        System.out.println(e);
    } catch (NumberFormatException e) {
        System.out.println(e);
    }
}

存在多个catch的时候,catch的顺序非常重要:子类必须写在前面。因为如果catch中存在父子类,而且父类在子类的前面,那么只会捕获到父类,而不能精确的捕获到子类相关的错误

例如:

public static void main(String[] args) {
    try {
        process1();
        process2();
        process3();
    } catch (IOException e) {
        System.out.println("IO error");
    } catch (UnsupportedEncodingException e) { // 永远捕获不到
        System.out.println("Bad encoding");
    }
}

对于上面的代码,UnsupportedEncodingException异常是永远捕获不到的,因为它是IOException的子类。当抛出UnsupportedEncodingException异常时,会被catch (IOException e) { ... }捕获并执行。

如果想要精确捕获子类的错误,那么就需要把子类放在前面

try {
        process1();
        process2();
        process3();
    } catch (UnsupportedEncodingException e) {
        System.out.println("Bad encoding");
    } catch (IOException e) {
        System.out.println("IO error");
    }

finally语句

无论是否有异常发生,如果我们都希望执行一些语句,例如判断捕获程序的结束。最常见的就是可以把执行语句写若干遍:正常执行的放到try中,每个catch再写一遍。例如:

try {
        process1();
        process2();
        process3();
        System.out.println("END");
    } catch (UnsupportedEncodingException e) {
        System.out.println("Bad encoding");
        System.out.println("END");
    } catch (IOException e) {
        System.out.println("IO error");
        System.out.println("END");
    }
//上述代码无论是否发生异常,都会执行System.out.println("END");这条语句。

java提供finally可以解决重复编写的问题,finally语句块保证有无错误都会执行。上述代码可以改写如下:

public static void main(String[] args) {
    try {
        process1();
        process2();
        process3();
    } catch (UnsupportedEncodingException e) {
        System.out.println("Bad encoding");
    } catch (IOException e) {
        System.out.println("IO error");
    } finally {
        System.out.println("END");
    }
}

finally的特点如下:

  1. finally语句不是必须的,可写可不写;
  2. finally总是最后执行。

如果没有发生异常,就正常执行try { ... }语句块,然后执行finally。如果发生了异常,就中断执行try { ... }语句块,然后跳转执行匹配的catch语句块,最后执行finally

finally的还有一个功能就是保证一些代码是必须执行的

捕获多种异常

如果某些异常的处理逻辑相同,就可以使用”|“把他们都合并在一起。

注意:异常本身不存在继承关系,得编写多条catch子句。

小结

  • 多个catch语句的匹配顺序非常重要,子类必须放在前面;
  • finally语句保证了有无异常都会执行,它是可选的;
  • 一个catch语句也可以匹配多个非继承关系的异常。