Java 异常类
最后修改时间:2025 年 4 月 13 日
java.lang.Exception
类是 Java 中所有异常的超类。 异常是运行时事件,会中断正常的执行流程并发出信号,表明需要处理这些问题以实现健壮的应用程序行为。 正确的异常管理可确保错误恢复,增强稳定性和改进调试。
Java 异常分为两个主要类别:检查型异常(编译时)和 非检查型异常(运行时)。 检查型异常必须显式处理,可以通过捕获它们或在方法签名中声明它们,而非检查型异常是由于编程错误而发生的,并且可以在没有强制处理的情况下传播。 了解异常类型和处理机制对于编写可靠、可维护的代码至关重要。
异常类层次结构
在 Java 的异常层次结构中,Exception
类直接位于 Throwable
之下。 它有两个关键子类:RuntimeException
(代表非检查型异常)和 IOException
(一种常见的检查型异常类型)。 这种区别决定了异常在代码中的管理方式。
java.lang.Throwable ├── java.lang.Error └── java.lang.Exception ├── java.lang.RuntimeException │ ├── java.lang.NullPointerException │ ├── java.lang.IllegalArgumentException │ ├── java.lang.IndexOutOfBoundsException │ └── ... ├── java.lang.IOException │ ├── java.lang.FileNotFoundException │ ├── java.lang.UnsupportedEncodingException │ └── ... ├── java.lang.ReflectiveOperationException ├── java.lang.InterruptedException └── Other checked exceptions
主要区别:检查型与非检查型异常
- 检查型异常: 这些异常必须使用
try-catch
进行处理,或者使用throws
声明。 示例:IOException
、SQLException
、InterruptedException
。 - 非检查型异常: 这些异常扩展了
RuntimeException
,通常是由于编程逻辑错误造成的,例如NullPointerException
和IllegalArgumentException
。 处理它们是可选的,但建议这样做。 - 错误 (Errors): 与异常不同,错误表示严重问题(例如,
OutOfMemoryError
),并且通常是不可恢复的。
检查型异常和非检查型异常之间的区别有助于开发人员预测故障点,改进程序流程并确保正确处理意外情况。
基本异常处理
Java 提供了 try-catch
块来处理异常。 try
块包含可能抛出异常的代码,而 catch
块定义了发生异常时如何处理该异常。 这可以防止程序突然终止。
在实践中,许多异常(例如除以零)都是通过在执行操作之前使用条件检查来避免的,而不是依赖于事后捕获它们。 积极主动的方法可以提高程序的稳定性并避免不必要的异常处理。
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; } }
此示例演示了基本的异常处理。 divide
方法在除以零时抛出 ArithmeticException
。 但是,在实际应用中,在执行除法之前检查零将是首选方法,以防止异常发生。
检查型与非检查型异常
检查型异常必须声明或处理,而非检查型异常则不需要。 检查型异常扩展了 Exception
但没有扩展 RuntimeException
。 非检查型异常扩展了 RuntimeException
或 Error
。
package com.zetcode; import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; public class Main { public static void main(String[] args) { // Unchecked exception (no need to declare) try { String str = null; System.out.println(str.length()); } catch (NullPointerException e) { System.out.println("NullPointerException caught"); } // Checked exception (must be handled) try { readFile("nonexistent.txt"); } catch (FileNotFoundException e) { System.out.println("File not found: " + e.getMessage()); } } public static void readFile(String path) throws FileNotFoundException { File file = new File(path); Scanner scanner = new Scanner(file); while (scanner.hasNextLine()) { System.out.println(scanner.nextLine()); } scanner.close(); } }
此示例对比了检查型异常和非检查型异常。 NullPointerException
是非检查型的,不需要声明。 FileNotFoundException
是检查型的,必须在方法签名中使用 throws 捕获或声明。
创建自定义异常
可以通过扩展 Exception 或 RuntimeException 来创建自定义异常。 它们应该提供与超类构造函数匹配的构造函数。 自定义异常对于特定于应用程序的错误情况很有用。
package com.zetcode; class InsufficientFundsException extends Exception { private double amount; public InsufficientFundsException(double amount) { super("Insufficient funds: " + amount); this.amount = amount; } public double getAmount() { return amount; } } class BankAccount { private double balance; public BankAccount(double balance) { this.balance = balance; } public void withdraw(double amount) throws InsufficientFundsException { if (amount > balance) { throw new InsufficientFundsException(amount - balance); } balance -= amount; } } public class Main { public static void main(String[] args) { BankAccount account = new BankAccount(500); try { account.withdraw(600); } catch (InsufficientFundsException e) { System.out.println(e.getMessage()); System.out.println("Missing amount: " + e.getAmount()); } } }
此示例显示了一个自定义的 InsufficientFundsException。 该异常包含有关缺失金额的附加信息。 当提款超过余额时,BankAccount 类会抛出此异常。 main 方法捕获并处理自定义异常。
多个 Catch 块
多个 catch 块可以处理不同的异常类型。 更具体的异常应该放在更一般的异常之前。 Java 7 引入了 multi-catch,用于在一个块中处理多个异常。
package com.zetcode; import java.util.InputMismatchException; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); try { System.out.print("Enter numerator: "); int numerator = scanner.nextInt(); System.out.print("Enter denominator: "); int denominator = scanner.nextInt(); int result = numerator / denominator; System.out.println("Result: " + result); } catch (InputMismatchException e) { System.out.println("Invalid input - must be integer"); } catch (ArithmeticException e) { System.out.println("Cannot divide by zero"); } catch (Exception e) { System.out.println("An unexpected error occurred"); } finally { scanner.close(); System.out.println("Scanner closed in finally block"); } } }
此示例演示了多个 catch 块。 InputMismatchException
处理非整数输入。 ArithmeticException
处理除以零。 更通用的 Exception
捕获任何其他错误。 finally 块确保扫描器始终关闭,无论是否发生异常。
Try-With-Resources
Try-with-resources 会自动关闭实现 AutoCloseable
的资源。 这消除了对显式 finally 块进行资源清理的需求。 它在 Java 7 中引入,以简化资源管理。
package com.zetcode; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class Main { public static void main(String[] args) { String path = "example.txt"; try (BufferedReader br = new BufferedReader(new FileReader(path))) { String line; while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { System.out.println("Error reading file: " + e.getMessage()); } } }
此示例使用 try-with-resources 读取文件。 BufferedReader 在 try 语句中声明,并在块退出时自动关闭。 这种方法比使用 finally 块进行手动资源管理更简洁。 如果文件读取失败,则捕获 IOException。
异常传播
异常向上调用堆栈传播,直到被捕获为止。 方法可以声明它们抛出但不处理的异常。 这允许在应用程序中的适当级别集中进行异常处理。
package com.zetcode; class DataProcessor { public void processData(String data) throws IllegalArgumentException { if (data == null || data.isEmpty()) { throw new IllegalArgumentException("Invalid data"); } System.out.println("Processing: " + data); } } class DataService { private DataProcessor processor = new DataProcessor(); public void handleData(String data) { try { processor.processData(data); } catch (IllegalArgumentException e) { System.out.println("Service error: " + e.getMessage()); // Could log error or perform recovery here } } } public class Main { public static void main(String[] args) { DataService service = new DataService(); service.handleData("Valid data"); service.handleData(""); // Will trigger exception } }
此示例显示了异常传播。 DataProcessor 针对无效数据抛出 IllegalArgumentException
。 DataService 捕获并处理此异常。 main 方法不需要处理该异常,因为它已在服务级别处理。 这演示了分层异常处理。
来源
在本文中,我们介绍了 Java Exception 类以及带有实际示例的异常处理。 正确的异常处理对于构建健壮且可维护的 Java 应用程序至关重要。
作者
列出所有Java教程。