Java 异常类型及示例

17 May 2025 | 8 分钟阅读

在 Java 中,异常是在程序执行过程中发生的事件,它会中断程序指令的正常流程。我们不希望发生且会限制代码正常执行的错误或异常被称为异常。在本节中,我们将重点介绍Java 中的异常类型以及它们之间的区别。

异常类型

异常可以分为两类

  1. 内置异常
    • 已检查异常
    • 未检查异常
  2. 用户定义异常
Types of Exception in Java

内置异常

已在Java 库中提供的异常称为内置异常。这些异常能够定义错误情况,以便我们理解出现此错误的原因。它们可以分为两大类,即受检异常非受检异常

已检查异常

受检异常被称为编译时异常,因为这些异常在编译时由编译器进行检查。编译器确保程序员是否处理了异常。程序员必须处理异常;否则,系统将显示编译错误。

受检异常示例

示例

编译并运行

输出

Main.java:5: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
        file_data = new FileInputStream("C:/Users/Desktop/Hello.txt");  
                    ^
Main.java:7: error: unreported exception IOException; must be caught or declared to be thrown
        while(( m = file_data.read() ) != -1) {  
                                  ^
Main.java:10: error: unreported exception IOException; must be caught or declared to be thrown
        file_data.close();  
                       ^
3 errors

在上面的代码中,我们尝试读取 Hello.txt 文件以在控制台上显示其数据。执行上述程序时,我们会收到以下异常:

  1. FileInputStream(File filename) 构造函数抛出 FileNotFoundException,这是一个受检异常。
  2. FileInputStream 类的 read() 方法抛出 IOException
  3. close() 方法也抛出 IOException。

处理受检异常

我们主要有两种方法可以处理这些异常。

使用 throws 关键字

异常发生在 main() 方法中。我们可以通过使用 throws 关键字在 main() 方法中声明异常来消除这些编译错误。由于父子关系,我们只声明 IOException,而不声明 FileNotFoundException。IOException 类是 FileNotFoundException 类的父类,因此 IOException 会自动处理此异常。我们将按以下方式声明异常:

当使用 throws 关键字处理 IOException 来编译和运行上述代码时,我们会得到以下输出:

Hello Java

使用 try-catch 块

我们也可以使用 try-catch 块来处理此异常。然而,我们上面使用的方式是不正确的。我们必须为每个异常提供有意义的消息,因为它更容易理解错误。我们将按以下方式使用 try-catch 块:

示例

编译并运行

输出

File Not Found!
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.io.FileInputStream.read()" because "<local1>" is null
	at Main.main(Main.java:12)

我们将在控制台上看到一条恰当的错误消息“文件未找到!”,因为在该位置没有 Hello.txt 文件。我们将在控制台上看到以下消息:

未检查异常

非受检异常受检异常恰恰相反。编译器不会在编译时检查这些异常。简而言之,如果程序抛出非受检异常,即使我们没有处理或声明它,程序也不会给出编译错误。通常,当用户在与程序交互时提供无效数据时,就会发生这种情况。

注意:由于父子关系,RuntimeException 类能够解决所有非受检异常。

非受检异常示例

ArithmeticException:除以零

示例

编译并运行

输出

Runtime Error:
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Main.main(Main.java:7)

在上述程序中,我们用 0 除以 35。代码将成功编译,但会在运行时抛出 ArithmeticException 错误。用 0 除以一个数会抛出除零异常,这是一个非受检异常。

让我们看另一个非受检异常的例子。

ArrayIndexOutOfBoundsException 示例

示例

编译并运行

输出

Runtime Error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 7 out of bounds for length 6
	at Main.main(Main.java:6)

在上面的代码中,我们试图获取位于位置 7 的元素,但数组的长度为 6。代码编译成功,但在运行时抛出 ArrayIndexOutOfBoundsException。

用户定义异常

Java 中,我们已经有一些内置的异常类,如 ArrayIndexOutOfBoundsException、NullPointerExceptionArithmeticException。这些异常仅限于在某些预定义的条件下触发。在 Java 中,我们可以通过继承 Exception 类来编写自己的异常类。我们可以使用 throw 关键字在特定条件下抛出自己的异常。要创建用户定义的异常,我们应该具备 try-catch 块和 throw 关键字的基本知识。

让我们编写一个 Java 程序并创建用户定义的异常。

示例

编译并运行

输出

Exception value = 5

解释

在上面的代码中,我们创建了两个类,即 MainNewExceptionMain 类包含 main() 方法,NewException 类是一个用户定义的异常类,它继承了 ExceptionNewException 类中,我们创建了一个整型变量 x 并在构造函数中为其赋值。为该变量赋值后,我们返回异常消息。

Main 类中,我们添加了一个 try-catch 块。在 try 块中,我们抛出异常,即 NewException,并向其传递一个整数。该值将被传递到 NewException 类并返回一条消息。我们在 catch 块中捕获该消息并在控制台上显示。

受检异常与非受检异常的区别

方面已检查异常未检查异常
编译时行为这些异常在编译时进行检查。这些异常也在编译时处理。这些异常与受检异常恰恰相反。这些异常在编译时不会被检查和处理。
层级结构它们是 Exception 的直接子类,但不是从 RuntimeException 类继承的。它们是 RuntimeException 类的直接子类。
编译器强制执行如果方法抛出受检异常,代码将出现编译错误。编译器本身无法处理该异常。代码将编译而不会出现任何错误,因为编译器忽略了这些异常。这些异常是编程逻辑中用户创建的错误的后果。
发生情况当失败的可能性很高时,通常会发生这些异常。这些异常通常是由于编程错误引起的。
示例常见的受检异常包括 IOException、DataAccessException、InterruptedException 等。常见的非受检异常包括 ArithmeticException、InvalidClassException、NullPointerException 等。
传播这些异常使用 throws 关键字进行传播。它们会自动传播。
处理要求需要提供 try-catch 和 try-finally 块来处理受检异常。对于非受检异常,这不是强制性的。

我们不希望发生且会限制程序正常执行的错误或异常被称为异常

结论

ArithmeticException、ArrayIndexOutOfBoundsExceptions、ClassNotFoundExceptions 等属于内置异常。有时,内置异常不足以解释或描述某些情况。为了描述这些情况,我们必须通过将一个异常类作为 Exception 类的子类来创建自己的异常。这些类型的异常属于用户定义异常

1. 下列哪项是 Java 中的受检异常?

  1. NullPointerException
  2. ArithmeticException
  3. IOException
  4. ArrayIndexOutOfBoundsException

答案:3)

解释:编译器使用 try-catch 或 throws 子句要求您处理受检异常。其他是非受检异常(RuntimeException 的子类),而 IOException 是受检异常。


2. 以下代码的输出是什么?

  1. 0
  2. 编译时错误
  3. 运行时异常:ArithmeticException
  4. 无限循环

答案:3)

解释:这是一个非受检异常的例子。当运行时除以零时,会引发 ArithmeticException。它编译成功但由于是非受检异常而无法执行。


3. 关于 Java 中的受检异常,以下哪项陈述是正确的?

  1. 不需要捕获或声明它们。
  2. 它们继承了 RuntimeException 类。
  3. 编译器在运行时检查它们。
  4. 它们必须被捕获或声明为抛出。

答案:4)

解释:受检异常必须使用 throws 关键字声明,或使用 try-catch 块手动处理。


4. 下列代码的输出是什么?

  1. 程序成功读取文件
  2. 运行时错误:文件未找到
  3. 编译时错误:未处理的异常类型 FileNotFoundException
  4. 无输出,无错误

答案:3)

解释:FileReader 抛出一个名为 FileNotFoundException 的受检异常,需要进行处理或声明。由于未声明或捕获,因此编译器会报错。


5. 识别异常类型。

抛出什么类型的异常,代码应如何处理?

  1. 受检异常:使用 throws 子句
  2. 非受检异常;包装在 try-catch 中(可选)
  3. 语法错误;声明字符串
  4. 编译错误;str 为 null

答案:2)

解释:此代码在运行时抛出称为 NullPointerException 的非受检异常。虽然可以使用 try-catch 来可选地处理它,但编译器不要求这样做。