Java异常处理:从基础到最佳实践
在Java编程中,异常处理是确保程序健壮性和稳定性的关键环节。本文将从异常的基础概念、处理机制、最佳实践,到实际代码示例,全面梳理Java异常处理的知识点,并结合课后练习题进行实战演练。
一、异常基础
1.1 异常的定义
异常是指程序运行过程中出现的非正常情况,如文件找不到、网络连接失败等。Java通过Throwable
类及其子类来表示异常。
1.2 异常体系
Throwable
:所有异常和错误的父类。Exception
:受检查异常(checked exception),必须被捕获或声明抛出。RuntimeException
:运行时异常(unchecked exception),不需要声明或捕获。
Error
:错误,通常表示不可恢复的严重问题,如OutOfMemoryError
。
1.3 异常的分类
- 受检查异常(checked exception) :如
IOException
,必须在方法签名中声明throws
,或者在方法体内用try-catch
捕获。 - 非受检查异常(unchecked exception) :如
RuntimeException
,不需要声明或捕获。
二、异常处理机制
2.1 try-catch-finally
try
代码块用于包裹可能抛出异常的代码,catch
用于捕获并处理异常,finally
用于执行清理工作,如关闭文件流或数据库连接。
java
try {
// 可能抛出异常的代码
} catch (Exception e) {
// 处理异常
} finally {
// 清理工作
}
2.2 try-with-resources
Java 7引入了try-with-resources
语法,用于自动关闭实现了AutoCloseable
接口的资源,简化了资源管理。
java
try (FileInputStream is = new FileInputStream("file.txt")) {
// 使用资源
} catch (IOException e) {
e.printStackTrace();
}
2.3 throw与throws
throw
:用于抛出一个异常对象。throws
:用于在方法签名中声明可能抛出的异常。
java
public void readFile() throws IOException {
throw new IOException("File not found");
}
三、异常处理的最佳实践
3.1 尽早抛出异常
尽早发现并抛出异常,可以简化问题排查,避免问题在程序中传播。
3.2 避免滥用异常
异常的创建和处理成本较高,应避免用异常来控制程序流程。例如,不要用try-catch
来判断文件是否存在,而应使用File.exists()
。
3.3 保留异常链
在捕获并重新抛出异常时,应保留异常链,以便后续排查问题。
java
throw new RuntimeException("Outer exception", e);
3.4 合理使用日志
在捕获异常时,应记录详细的日志信息,包括异常类型、消息和堆栈信息。
java
logger.error("Error occurred", e);
3.5 不要忽略异常
除非有充分的理由,否则不要忽略捕获的异常。如果确实需要忽略,应在注释中说明原因。
java
try {
// 可能抛出异常的代码
} catch (Exception e) {
// 忽略异常,但需说明原因
}
四、课后练习题解析
4.1 grep-file
题目要求实现一个方法,找到文件中第一个包含指定文本的行号。如果文件不存在或无法读取,抛出IllegalArgumentException
。
java
public static int grep(File target, String text) {
try (FileInputStream inputStream = new FileInputStream(target);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
int count = 0;
String str;
while ((str = bufferedReader.readLine()) != null) {
count++;
if (str.contains(text)) {
return count;
}
}
return -1;
} catch (IOException e) {
throw new IllegalArgumentException("File not found or cannot be read", e);
}
}
4.2 fix-exception-handling
题目要求修复数据库连接代码中的异常处理问题。以下是改进后的代码:
java
public static void main(String[] args) {
File projectDir = new File(System.getProperty("basedir", System.getProperty("user.dir")));
String jdbcUrl = "jdbc:h2:file:" + new File(projectDir, "test").getAbsolutePath();
System.out.println(jdbcUrl);
try (Connection connection = DriverManager.getConnection(jdbcUrl, "sa", "")) {
PreparedStatement statement = connection.prepareStatement("select * from PULL_REQUESTS where number > ?");
statement.setInt(1, 0);
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
System.out.println(
resultSet.getInt(1)
+ " "
+ resultSet.getString(2)
+ " "
+ resultSet.getString(3));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
五、总结
本文全面介绍了Java异常处理的基础知识、处理机制和最佳实践,并通过课后练习题加深了对异常处理的理解。掌握异常处理技巧,可以有效提升程序的健壮性和可维护性。在实际开发中,合理使用异常处理机制,避免滥用异常,保留异常链,并记录详细日志,是确保程序稳定运行的重要保障。