ZetCode

Java Throwable 类

最后修改时间:2025 年 4 月 13 日

java.lang.Throwable 类是 Java 中所有错误和异常的超类。它是 Java 异常处理机制的基础。理解 Throwable 对于正确的错误处理至关重要。

Throwable 包含创建时执行堆栈的快照。它提供了访问此堆栈跟踪和获取错误原因的方法。所有异常和错误都继承自 Throwable,使其成为 Java 错误层次结构的根。

Throwable 类方法

Throwable 类提供了几种用于错误处理和调试的方法。主要方法包括 getMessagegetCauseprintStackTracegetStackTrace。这些方法有助于有效地诊断和处理错误。

public class Throwable implements Serializable {
    public Throwable() {...}
    public Throwable(String message) {...}
    public Throwable(String message, Throwable cause) {...}
    public Throwable(Throwable cause) {...}
    public String getMessage() {...}
    public String getLocalizedMessage() {...}
    public Throwable getCause() {...}
    public void printStackTrace() {...}
    public StackTraceElement[] getStackTrace() {...}
    public void setStackTrace(StackTraceElement[] stackTrace) {...}
    public final void addSuppressed(Throwable exception) {...}
    public final Throwable[] getSuppressed() {...}
}

上面的代码显示了 Throwable 类提供的主要方法。这些方法允许检查错误详细信息、原因以及发生错误时的执行堆栈跟踪。

基本异常处理

此示例演示了使用 try-catch 块的基本异常处理。我们捕获除以零时发生的 ArithmeticException。 catch 块打印异常消息和堆栈跟踪。

Main.java
package com.zetcode;

public class Main {

    public static void main(String[] args) {
        try {
            int result = divide(10, 0);
            System.out.println("Result: " + result);
        } catch (ArithmeticException e) {
            System.out.println("Error: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    public static int divide(int a, int b) {
        return a / b;
    }
}

执行时,此代码会捕获除以零引发的 ArithmeticException。 catch 块打印错误消息和完整的堆栈跟踪,显示异常发生的位置。 这有助于调试问题。

自定义异常类

此示例显示了如何通过扩展 Exception 来创建自定义异常。我们定义了一个 InsufficientFundsException,其中包括当前余额和请求的金额。这提供了有关错误的更多上下文。

Main.java
package com.zetcode;

class InsufficientFundsException extends Exception {
    private double balance;
    private double amount;
    
    public InsufficientFundsException(double balance, double amount) {
        super("Insufficient funds: balance=" + balance + ", amount=" + amount);
        this.balance = balance;
        this.amount = amount;
    }
    
    public double getBalance() { return balance; }
    public double getAmount() { return amount; }
}

class Account {
    private double balance;
    
    public Account(double balance) { this.balance = balance; }
    
    public void withdraw(double amount) throws InsufficientFundsException {
        if (amount > balance) {
            throw new InsufficientFundsException(balance, amount);
        }
        balance -= amount;
    }
}

public class Main {

    public static void main(String[] args) {
        Account account = new Account(100);
        try {
            account.withdraw(150);
        } catch (InsufficientFundsException e) {
            System.err.println(e.getMessage());
            System.err.println("Short by: " + (e.getAmount() - e.getBalance()));
        }
    }
}

自定义异常提供了有关错误条件的详细信息。 捕获后,我们可以访问标准消息和附加字段。 这使得错误处理更具信息性和精确性。

链式异常

Java 允许链接异常,以便在包装异常时保留原始原因。此示例演示了如何使用接受原因的 Throwable 构造函数来创建和处理链式异常。

Main.java
package com.zetcode;

import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try {
            processFile("nonexistent.txt");
        } catch (ApplicationException e) {
            System.err.println("Caught: " + e.getMessage());
            System.err.println("Original cause: " + e.getCause().getMessage());
            e.getCause().printStackTrace();
        }
    }
    
    public static void processFile(String filename) throws ApplicationException {
        try {
            // Simulate file operation that fails
            throw new IOException("File not found: " + filename);
        } catch (IOException e) {
            throw new ApplicationException("Failed to process file", e);
        }
    }
}

class ApplicationException extends Exception {
    public ApplicationException(String message, Throwable cause) {
        super(message, cause);
    }
}

此示例显示了一个常见的模式,其中低级别的 IOException 被包装在高级别的 ApplicationException 中。 保留了原始原因,以后可以访问。 这在提供特定于应用程序的语义的同时,保持了完整的错误上下文。

打印堆栈跟踪

Throwable 类提供了几种打印堆栈跟踪的方法。 此示例演示了访问和打印堆栈跟踪信息的不同方法,包括标准 printStackTrace 和 getStackTrace 方法。

Main.java
package com.zetcode;

public class Main {

    public static void main(String[] args) {
        try {
            method1();
        } catch (Exception e) {
            // Standard stack trace to stderr
            e.printStackTrace();
            
            // Print stack trace to System.out
            e.printStackTrace(System.out);
            
            // Access stack trace elements programmatically
            System.out.println("\nStack trace elements:");
            for (StackTraceElement element : e.getStackTrace()) {
                System.out.println(element);
            }
        }
    }
    
    public static void method1() {
        method2();
    }
    
    public static void method2() {
        method3();
    }
    
    public static void method3() {
        throw new RuntimeException("Test exception");
    }
}

此代码演示了访问堆栈跟踪信息的三种方法。 标准 printStackTrace 输出到 stderr,而重载版本可以重定向输出。 getStackTrace 方法允许以编程方式访问每个堆栈帧。

抑制异常

Java 7 引入了抑制异常来处理发生多个异常的情况,例如在 try-with-resources 块中。此示例显示了如何使用 getSuppressed 访问抑制的异常。

Main.java
package com.zetcode;

class Resource implements AutoCloseable {
    private String name;
    
    public Resource(String name) { this.name = name; }
    
    public void use() throws Exception {
        throw new Exception("Error using resource " + name);
    }
    
    @Override
    public void close() throws Exception {
        throw new Exception("Error closing resource " + name);
    }
}

public class Main {

    public static void main(String[] args) {
        try (Resource res1 = new Resource("1");
             Resource res2 = new Resource("2")) {
            res1.use();
            res2.use();
        } catch (Exception e) {
            System.out.println("Caught: " + e.getMessage());
            System.out.println("Suppressed exceptions:");
            for (Throwable t : e.getSuppressed()) {
                System.out.println(" - " + t.getMessage());
            }
        }
    }
}

在此 try-with-resources 示例中,use() 和 close() 方法都会抛出异常。 主要异常是来自 use() 的异常,而 close() 异常被添加为抑制的异常。 这会将所有错误信息保存在单个异常对象中。

错误 vs 异常

此示例演示了 Errors 和 Exceptions 之间的区别,它们都扩展了 Throwable。 Errors 通常表示应用程序不应尝试捕获的严重问题,而 Exceptions 表示可能被处理的条件。

Main.java
package com.zetcode;

public class Main {

    public static void main(String[] args) {
        // Handling a checked exception
        try {
            throw new Exception("This is a regular exception");
        } catch (Exception e) {
            System.out.println("Caught Exception: " + e.getMessage());
        }
        
        // Attempting to handle an Error (not recommended)
        try {
            throw new OutOfMemoryError("This is an error");
        } catch (Error e) {
            System.out.println("Caught Error: " + e.getMessage());
        }
        
        // Uncaught Error will terminate the program
        throw new StackOverflowError("This will terminate the program");
    }
}

该示例表明,虽然 Errors 和 Exceptions 都可以被捕获,但 Errors 通常表示无法恢复的条件。 该程序尝试处理 OutOfMemoryError(在实践中不推荐),最后抛出一个未捕获的 StackOverflowError,从而终止执行。

来源

Java Throwable 类文档

本教程介绍了 Throwable 类,它是 Java 错误处理的基础。 我们探讨了异常处理、自定义异常、链接、堆栈跟踪、抑制异常以及 Error/Exception 的区别。

作者

我的名字是 Jan Bodnar,我是一位敬业的程序员,在这个领域拥有多年的经验。 我于 2007 年开始撰写编程文章,至今已撰写了超过 1,400 篇文章和八本电子书。 凭借超过八年的教学经验,我致力于分享我的知识并帮助其他人掌握编程概念。

列出所有Java教程