1. try-catch

使用trycatch关键字可以捕获异常,通常try-catch代码块放在异常可能发生的地方,用以保护代码稳定运行:

  1. try {
  2. // 程序代码
  3. } catch (ExceptionName e) {
  4. // catch代码块
  5. }

catch语句包含要捕获异常类型的声明,当try代码块中发生异常时,catch块就会被检查。如果发生的异常包含在catch块中,异常则会被传递到该catch块,本质上和传递参数给方法是一样的。

如果一个try代码块跟随多个catch代码块,我们称之为多重捕获

  1. try {
  2. // 程序代码
  3. } catch (ExceptionName1 e1) {
  4. // catch代码块
  5. } catch (ExceptionName2 e2) {
  6. // catch代码块
  7. } catch (ExceptionName3 e3) {
  8. // catch代码块
  9. }

💡 catch代码块要先将作用范围小的放在前面,作用范围大的依次往后放。如果一开始就捕获Exception的话,那么其他异常都不会被捕获了。

2. throws/throw

如果一个方法没有捕获一个检查性异常,那么该方法必须使用throws关键字来声明。throws关键字放在方法签名的尾部,也可以使用throw关键字抛出一个异常。同时,一个方法也可以声明抛出多个异常,异常之间使用逗号隔开。

| ```java public static void main(String[] args) throws InterruptedException{}

  1. | ```java
  2. public static void main(String[] args)
  3. throws InterruptedException, IOException {}

| | —- | —- |

3. finally

finally关键字用来创建try代码块后面执行的代码块,无论异常是否发生,finally代码块总是会被执行。在finally代码块中,可以执行收尾性代码。另外,finally代码块出啊先在catch代码块的最后。

  1. try {
  2. // 程序代码
  3. } catch (ExceptionName1 e1) {
  4. // catch代码块
  5. } catch (ExceptionName2 e2) {
  6. // catch代码块
  7. } finally {
  8. // finally代码块
  9. }

以下情况下,finally代码块不会被执行:

  • finally代码块中发生了异常,那么该代码块不会被完整地执行
  • 在前面的代码中使用了System.exit()退出了程序
  • 程序所在线程死亡
  • CPU 已经关闭

    4. try-catch-finally执行顺序

    | ```java public class TryCatchFinally { public static int test() {

    1. int i = 1;
    2. try {
    3. i++;
    4. System.out.println("Try i = " + i);
    5. } catch (Exception e) {
    6. i--;
    7. System.out.println("Catch i = " + i);
    8. } finally {
    9. i = 10;
    10. System.out.println("Finally i = " + i);
    11. }
    12. return i;

    }

    public static void main(String[] args) {

    1. int result = test();
    2. System.out.println(result);

    } }

// Try i = 2 // Finally i = 10 // 10

  1. | ```java
  2. public class TryCatchFinally {
  3. public static int test() {
  4. int i = 1;
  5. try {
  6. i++;
  7. System.out.println("Try i = " + i);
  8. throw new Exception();
  9. } catch (Exception e) {
  10. i--;
  11. System.out.println("Catch i = " + i);
  12. } finally {
  13. i = 10;
  14. System.out.println("Finally i = " + i);
  15. }
  16. return i;
  17. }
  18. public static void main(String[] args) {
  19. int result = test();
  20. System.out.println(result);
  21. }
  22. }
  23. // Try i = 1
  24. // Finally i = 10
  25. // 10

| | —- | —- | | ```java public class TryCatchFinally { public static int test() { int i = 1; try { i++; System.out.println(“Try i = “ + i); return i; } catch (Exception e) { i—; System.out.println(“Catch i = “ + i); } finally { i = 10; System.out.println(“Finally i = “ + i); } return i; }

  1. public static void main(String[] args) {
  2. int result = test();
  3. System.out.println(result);
  4. }

}

// Try i = 2 // Finally i = 10 // 2

  1. | ```java
  2. public class TryCatchFinally {
  3. public static int test() {
  4. int i = 1;
  5. try {
  6. i++;
  7. System.out.println("Try i = " + i);
  8. return i;
  9. } catch (Exception e) {
  10. i--;
  11. System.out.println("Catch i = " + i);
  12. return i;
  13. } finally {
  14. i = 10;
  15. System.out.println("Finally i = " + i);
  16. return i;
  17. }
  18. }
  19. public static void main(String[] args) {
  20. int result = test();
  21. System.out.println(result);
  22. }
  23. }
  24. // Try i = 2
  25. // Finally i = 10
  26. // 3

|

如果finally代码块中包含return语句,那么程序将直接忽略try代码块中的return语句。

  • 对于异常的使用有一个不成文的约定:尽量在某个集中的位置进行统一处理,不要到处使用try-catch,否则代码会变得混乱不看。
  • 按照程序员的惯性认知,当遇到return语句的时候,执行函数会立刻返回。但是在 JAVA 语言中,如果存在finally代码块的话就会有例外。除了return语句,try代码块中break或者continue语句也可能使控制权进入finally代码块。
  • 不要在try代码块中调用returnbreak或者continue语句,万一无法避免,一定要确保finally的存在不会改变方法的返回值。
  • 方法返回值有两种类型:值类型与对象引用。对于对象引用,要特别小心,如果在finally代码块中返回的对象成员属性进行了修改,即使不在finally块中显式调用return语句,这个修改也会作用在返回值上。

:::info 💡 注意点

  1. 尽量不要捕获类似Exception这样的通用异常,而是应该捕获特定异常。
  2. 不要生吞异常,这是异常处理中特别需要注意的事情,否则将导致难以诊断的诡异情况,该抛出异常时还是应该将异常抛出,以便后续代码的优化。 :::