Java 异常处理
异常 (Exception) 是在程序执行期间发生的、中断程序正常指令流的事件。Java 提供了一个强大的异常处理框架,允许开发者优雅地捕获和处理这些错误,从而创建更健壮、更可靠的应用程序。
什么是异常?
在 Java 中,异常是一个对象,它封装了关于错误的详细信息,例如错误的类型和程序出错时的状态。当错误发生时,系统会创建一个异常对象并将其“抛出”(throw)。
异常的分类
所有异常对象都是 java.lang.Throwable 类的子类。Throwable 有两个主要的子类:Error 和 Exception。
Error: 表示严重的问题,通常是应用程序无法处理的,例如OutOfMemoryError(内存溢出)或StackOverflowError(栈溢出)。程序通常不应该尝试捕获Error。Exception: 表示应用程序可以处理的异常情况。它又分为两类:- 受检异常 (Checked Exceptions): 这类异常在编译时就必须被处理,否则代码无法通过编译。通常是程序外部的、不可预见的错误,如
IOException(文件未找到)。开发者必须使用try-catch捕获或使用throws声明抛出。 - 非受检异常 (Unchecked Exceptions / Runtime Exceptions): 这类异常在编译时不被检查,通常是由程序逻辑错误引起的,例如
NullPointerException(空指针引用)、ArrayIndexOutOfBoundsException(数组越界)或ArithmeticException(算术错误,如除以零)。虽然可以捕获它们,但更好的做法是修复代码逻辑来避免它们。
- 受检异常 (Checked Exceptions): 这类异常在编译时就必须被处理,否则代码无法通过编译。通常是程序外部的、不可预见的错误,如
try-catch 语句
这是处理异常的核心机制。将可能抛出异常的代码放在 try 块中,并使用 catch 块来捕获和处理特定类型的异常。
public class TryCatchExample {
public static void main(String[] args) {
try {
// 可能会导致异常的代码
int[] numbers = {1, 2, 3};
System.out.println(numbers[5]); // 数组越界
} catch (ArrayIndexOutOfBoundsException e) {
// 捕获并处理异常
System.out.println("发生错误:数组索引超出范围!");
// 打印异常的堆栈跟踪信息,便于调试
e.printStackTrace();
}
System.out.println("程序继续执行...");
}
}一个 try 块后面可以跟多个 catch 块,以处理不同类型的异常。
finally 关键字
finally 块中的代码无论是否发生异常,都保证会被执行(除非 JVM 退出)。它通常用于释放资源,如关闭文件流或数据库连接。
import java.io.*;
public class FinallyExample {
public static void main(String[] args) {
PrintWriter writer = null;
try {
writer = new PrintWriter(new FileWriter("output.txt"));
writer.println("Hello, World!");
} catch (IOException e) {
System.err.println("文件写入失败: " + e.getMessage());
} finally {
// 确保 writer 总是被关闭
if (writer != null) {
writer.close();
System.out.println("PrintWriter 已关闭。");
}
}
}
}throw 和 throws 关键字
throw: 用于在代码中主动抛出一个异常对象。通常用于报告自定义的错误条件。javapublic void checkAge(int age) { if (age < 18) { throw new IllegalArgumentException("年龄必须大于或等于 18 岁"); } System.out.println("年龄合法。"); }throws: 用在方法签名中,声明该方法可能会抛出一种或多种类型的受检异常。它告诉方法的调用者,调用此方法时必须处理这些声明的异常。javaimport java.io.IOException; // 声明此方法可能抛出 IOException public void readFile(String filePath) throws IOException { // ... 读取文件的代码 ... } // 调用者必须处理这个异常 public void processFile() { try { readFile("myFile.txt"); } catch (IOException e) { System.err.println("处理文件时出错。"); } }
try-with-resources 语句 (Java 7+)
对于实现了 java.lang.AutoCloseable 接口的资源(如文件流、数据库连接),try-with-resources 语句可以极大地简化资源管理。它能确保在 try 块执行完毕后,资源被自动关闭,无需手写 finally 块。
import java.io.*;
public class TryWithResourcesExample {
public static void main(String[] args) {
// writer 会在 try 块结束时自动关闭
try (PrintWriter writer = new PrintWriter(new FileWriter("log.txt"))) {
writer.println("这是一个自动管理的日志条目。");
} catch (IOException e) {
System.err.println("日志写入失败: " + e.getMessage());
}
}
}这是现代 Java 中处理资源的推荐方式。