引言:为什么错误处理对Java开发者至关重要
任何超越"Hello, World!"的程序都会遇到意外情况:用户输入字母而非数字、文件未找到、网络不可用。在Java中,为此开发了强大而优雅的异常机制。得体的错误处理不仅仅是"对问题视而不见",而是创建有韧性、可预测且安全的代码。
在本文中,我们将分析不仅经典的try/catch结构,还有高级技术:try-with-resources、创建自定义异常以及最佳实践,这些都将帮助您编写专业的Java代码。
1. 基础:异常层次结构与try/catch/finally结构
在捕获错误之前,需要理解它们的本质。在Java中,所有异常都是Throwable类的子类。主要分支是Exception(可以且应该处理的异常)和Error(处理无意义的JVM关键错误)。
在Exception内部的关键划分是受检异常和非受检异常。
- 受检异常(例如
IOException、SQLException)——编译器强制您处理它们。这些是可预见的外部故障。 - 非受检异常(
RuntimeException的子类:NullPointerException、ArrayIndexOutOfBoundsException)——程序中的逻辑错误。编译器不要求处理它们,但这并不意味着可以忽略。
基本try-catch-finally结构
最常见的错误处理方式是包含"危险"代码的try块,以及一个或多个用于捕获特定类型异常的catch块。
import java.io.*;
public class ReadFileExample { public static void main(String[] args) { BufferedReader reader = null; try { reader = new BufferedReader(new FileReader("data.txt")); String line = reader.readLine(); System.out.println("Read: " + line); } catch (FileNotFoundException e) { System.err.println("Error: File not found! " + e.getMessage()); } catch (IOException e) { System.err.println("Input/Output error: " + e.getMessage()); } finally { // finally ALWAYS executes, even if there was an exception or return try { if (reader != null) { reader.close(); // Important to close the resource } } catch (IOException e) { System.err.println("Error closing file: " + e.getMessage()); } } }}重要提示:finally块用于确保资源清理(关闭文件、数据库连接)。然而,从Java 7开始,出现了一种更优雅的方式。
2. 现代方法:try-with-resources(Java 7+)
忘记关闭文件或连接是初学者最常见的错误之一。try-with-resources结构会自动关闭所有实现了AutoCloseable(或Closeable)接口的资源。代码变得更短、更清晰、更安全。
import java.io.*;
public class TryWithResourcesExample { public static void main(String[] args) { // Resources are declared in parentheses after try try (BufferedReader reader = new BufferedReader(new FileReader("data.txt")); BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) {
String line; while ((line = reader.readLine()) != null) {