Menu
CoddyTech

异常类层次结构

本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 59 课,共 87 课。

Java 的异常处理系统建立在以 Throwable 类为根的组织良好的类层次结构之上。了解这一层次结构有助于你更有效地捕获和处理异常。

最顶层是 Throwable,它是所有异常和错误的父类。它有两个直接子类:

Throwable
├── Error          // 严重问题(不要捕获这类错误)
└── Exception      // 可恢复的问题
    └── RuntimeException  // 非受检异常

错误表示应用程序不应尝试处理的严重问题,例如 OutOfMemoryError 或 StackOverflowError。这些错误表明 JVM 本身存在根本性问题。

Exception 是你最常使用的分支。它分为两类:已检查异常(Exception 的直接子类)和未检查异常(RuntimeException 的子类)。

// 常见的异常类
Exception
├── IOException           // 文件或网络问题
├── SQLException          // 数据库问题
└── RuntimeException
    ├── NullPointerException
    ├── ArrayIndexOutOfBoundsException
    └── IllegalArgumentException

由于异常是类,因此它们遵循继承规则。捕获父异常类型时,也会捕获它的所有子类:

try {
    // 一些代码
} catch (Exception e) {
    // 捕获所有异常(通常范围太广)
}
try {
    // 一些代码
} catch (RuntimeException e) {
    // 只捕获运行时异常及其子类的异常
}

这个层级结构让你在处理错误时,可以根据需要选择具体或通用的程度,也是创建自定义异常的基础。

challenge icon

挑战

简单

让我们构建一个异常分析器,演示 Java 的异常层次结构在实际中的工作方式!你将创建一个系统,在不同的具体层级捕获异常,并报告捕获到的类型。

你将把代码分成三个文件:

  • ExceptionThrower.java:创建一个类,根据输入触发不同类型的异常。这个类应包含三个静态方法:

    triggerRuntime(String type) - 根据类型字符串抛出不同的运行时异常:

    • 如果 type 是 "null",则抛出带有消息 "Null value encountered" 的 NullPointerException
    • 如果 type 是 "index",则抛出带有消息 "Invalid index" 的 ArrayIndexOutOfBoundsException
    • 如果 type 是 "argument",则抛出带有消息 "Bad argument" 的 IllegalArgumentException

    triggerArithmetic() - 抛出带有消息 "Division error" 的 ArithmeticException

    triggerGeneric() - 抛出带有消息 "Generic runtime error" 的 IllegalStateException(其层次结构为 Exception > RuntimeException > IllegalStateException)

  • ExceptionAnalyzer.java:创建一个类,在不同的异常层次捕获异常,并识别捕获到的异常。包含以下静态方法:

    analyzeSpecific(String type) - 在 try 块中调用 ExceptionThrower.triggerRuntime(type)。分别为 NullPointerException、ArrayIndexOutOfBoundsException 和 IllegalArgumentException 编写 catch 块。对于每种异常,打印:Caught specific: [exception class simple name],然后打印 Message: [exception message]

    analyzeWithParent() - 在 try 块中调用 ExceptionThrower.triggerArithmetic()。使用 RuntimeException(父类型)捕获异常。打印:Caught via parent: RuntimeException,然后打印 Actual type: [exception class simple name]

    analyzeWithGrandparent() - 在 try 块中调用 ExceptionThrower.triggerGeneric()。使用 Exception(层次结构中更高的类型)捕获异常。打印:Caught via grandparent: Exception,然后打印 Actual type: [exception class simple name]

  • Main.java:整合你的异常分析器!你将接收一个输入:异常类型字符串(可以是 "null"、"index" 或 "argument")。

    首先,打印 === Specific Catch ===,并使用输入调用 analyzeSpecific。

    然后打印一个空行、=== Parent Catch ===,并调用 analyzeWithParent。

    最后,打印一个空行、=== Grandparent Catch ===,并调用 analyzeWithGrandparent。

你将接收一个输入:要触发的异常类型("null"、"index" 或 "argument")。

使用 e.getClass().getSimpleName() 获取异常的类名,并使用 e.getMessage() 获取异常消息。这个挑战展示了捕获父异常类型时也会捕获它的所有子类型,这是决定异常处理应当具体到什么程度时的一个关键概念!

亲手试试

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String type = scanner.nextLine();
        
        // TODO: 输出 "=== Specific Catch ===",并调用 ExceptionAnalyzer.analyzeSpecific(type)
        
        // TODO: 先输出一个空行,再输出 "=== Parent Catch ===",然后调用 ExceptionAnalyzer.analyzeWithParent()
        
        // TODO: 先输出一个空行,再输出 "=== Grandparent Catch ===",然后调用 ExceptionAnalyzer.analyzeWithGrandparent()
    }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Java 在线编译器