异常

异常 属于 Java

25 个练习

关于 异常

Java 编程语言使用异常来处理错误和其他异常事件。

什么是异常

异常是程序执行期间发生的、会打断指令正常流程的事件。 在 Java 中,异常是显式抛出的,抛出异常的动作称为_抛出异常_。 处理异常的动作称为_捕获异常_。

在 Java 中,所有异常都是 Exception 类的子类,而 Exception 类本身又是 Throwable 的子类。

Java 将异常分为两类:

  1. 受检异常
  2. 非受检异常

受检异常

_受检异常_是应用程序应当预见、并能从中恢复的异常情况。 受检异常的一个例子是 FileNotFoundException,当方法试图读取一个不存在的文件时就会发生。

这类异常在编译期检查:抛出受检异常的方法应当在其方法签名中说明这一点;调用可能抛出受检异常的方法的代码,必须处理该异常,否则代码无法通过编译。

所有受检异常都是 Exception 的子类,且不继承 RuntimeException。

非受检异常

_非受检异常_是应用程序通常无法预见、也无法从中恢复的异常情况。 非受检异常的一个例子是 NullPointerException,当方法期望一个非 null 值、却收到 null 时就会发生。

这类异常不在编译期检查:抛出非受检异常的方法不要求在其方法签名中说明这一点;调用可能抛出非受检异常的方法的代码,也不必处理它。

所有非受检异常都继承自 RuntimeException,而 RuntimeException 本身又继承自 Exception。

抛出异常

Java 中的方法可以使用 throw 语句抛出一个异常。

抛出受检异常

从方法中抛出受检异常时,必须使用 throws 关键字在方法签名中说明这一点,如下例所示。 这会迫使调用方的代码预见到可能抛出异常,并相应地处理它。

public class InsufficientBalanceException extends Exception {

}

public class BankAccount {
  public void withdraw(double amount) throws InsufficientBalanceException {
    if (balance < amount) {
      throw new InsufficientBalanceException();
    }

    // rest of the method implementation
  }
}

抛出非受检异常

从方法中抛出非受检异常时,不要求在方法签名中说明这一点,尽管也支持这样做。

public class BankAccount {
  public void withdraw(double amount) {
    if (amount < 0) {
      throw new IllegalArgumentException("Cannot withdraw a negative amount");
    }

    // rest of the method implementation
  }
}

处理异常

在 Java 中,处理异常要使用 try、catch 和 finally 关键字。

  • 可能抛出异常的代码语句应当放在 try 块中。
  • try 块后面跟着一个或多个 catch 块,用来捕获 try 块中抛出的异常。
  • catch 块后面可选地跟一个 finally 块,它总是在 try 块之后执行,无论是否抛出了异常。

下面的例子展示了这些关键字如何工作:

public class ATM {
  public void withdraw(BankAccount bankAccount, double amount) {
    try {
      System.out.println("Withdrawing " + amount);
      bankAccount.withdraw(amount);
      System.out.println("Withdrawal succeeded");
    } catch (InsufficientBalanceException) {
      System.out.println("Withdrawal failed: insufficient balance");
    } catch (RuntimeException e) {
      System.out.println("Withdrawal failed: " + e.getMessage());
    } finally {
      System.out.println("Current balance: " + bankAccount.getBalance());
    }
  }
}

在这个例子中,没有抛出异常时,会打印以下内容:

Withdrawing 10.0
Withdrawal succeeded
Current balance: 5.0

不过,如果 bankAccount.withdraw(amount) 语句抛出了 InsufficientBalanceException,则会打印以下内容:

Withdrawing 10.0
Withdrawal failed: insufficient balance
Current balance: 5.0

或者,如果 bankAccount.withdraw(amount) 抛出了非受检异常,则会打印以下内容:

Withdrawing -10.0
Withdrawal failed: Cannot withdraw a negative amount
Current balance: 5.0

错误

Java 还有一个单独的类别,称为_错误_,指的是应用程序外部的严重问题。 错误的一个例子是 OutOfMemoryError,当应用程序试图使用超过系统可用内存的内存时就会发生。

和非受检异常一样,错误也不在编译期检查。 区别在于,它们代表系统层面的问题,通常由 Java 虚拟机或环境抛出,而不是由应用程序抛出。 应用程序通常不应尝试捕获或处理它们。

Java 中的所有错误都继承自 Error 类。

什么时候不该使用异常

如前所述,异常是会打断指令正常流程的事件,用于处理_异常事件_。 因此,不建议在应用程序中使用异常来控制流程。

通过 GitHub 编辑 该链接会在新窗口或标签页中打开

学习 异常