第7章 异常处理
1. 异常概述与异常体系结构
1.1 异常的定义
- 异常:程序执行过程中发生的不正常情况。
- 错误类型:
- Error:JVM无法解决的严重问题,如
StackOverflowError
、OutOfMemoryError
。 - Exception:可以通过代码处理的异常,如空指针、数组越界等。
1.2 异常分类
- 运行时异常(RuntimeException):编译器不强制处理,通常是逻辑错误,如
NullPointerException
、ArithmeticException
。 - 编译时异常(Checked Exception):编译器强制处理,通常是外部因素导致的异常,如
IOException
、ClassNotFoundException
。
异常类型对比表
特性 | 运行时异常(RuntimeException) | 编译时异常(Checked Exception) |
---|
继承关系 | 继承RuntimeException | 直接继承Exception |
处理要求 | 不强制处理 | 必须显式处理 |
产生原因 | 代码逻辑错误 | 外部资源问题 |
典型示例 | NullPointerException, ClassCastException | IOException, SQLException |
最佳处理方式 | 修复代码逻辑 | try-catch或throws声明 |
1.3 异常体系结构
Throwable
├── Error
│ ├── StackOverflowError
│ └── OutOfMemoryError
└── Exception├── RuntimeException│ ├── NullPointerException│ ├── ArithmeticException│ └── ArrayIndexOutOfBoundsException└── IOException├── FileNotFoundException└── EOFException
树状图
2. 常见异常
2.1 常见运行时异常
异常类型 | 描述 | 示例代码 |
---|
NullPointerException | 空指针异常 | String str = null; System.out.println(str.length()); |
ArrayIndexOutOfBoundsException | 数组越界异常 | int[] arr = new int[3]; System.out.println(arr[3]); |
ArithmeticException | 算术异常(如除零) | int a = 10 / 0; |
ClassCastException | 类型转换异常 | Object obj = new Date(); String str = (String) obj; |
2.2 常见编译时异常
异常类型 | 描述 | 示例代码 |
---|
IOException | 输入输出异常 | FileInputStream fis = new FileInputStream("file.txt"); |
FileNotFoundException | 文件未找到异常 | FileInputStream fis = new FileInputStream("nonexistent.txt"); |
ClassNotFoundException | 类未找到异常 | Class.forName("com.example.NonExistentClass"); |
3. 异常处理机制
异常处理机制流程图
3.1 try-catch-finally
3.1.1 语法
try {
} catch (ExceptionType1 e) {
} catch (ExceptionType2 e) {
} finally {
}
3.1.2 执行流程
- try块:执行可能抛出异常的代码。
- catch块:捕获并处理异常。
- finally块:无论是否发生异常,都会执行。
3.1.3 示例
public class ExceptionTest {public static void main(String[] args) {try {int a = 10 / 0; } catch (ArithmeticException e) {System.out.println("捕获到异常:" + e.getMessage());} finally {System.out.println("finally块执行");}}
}
3.2 throws
3.2.1 语法
public void method() throws ExceptionType {
}
3.2.2 示例
public class ThrowsTest {public static void main(String[] args) {try {readFile();} catch (IOException e) {e.printStackTrace();}}public static void readFile() throws IOException {FileInputStream fis = new FileInputStream("file.txt");int b = fis.read();while (b != -1) {System.out.print((char) b);b = fis.read();}fis.close();}
}
4. 手动抛出异常
4.1 语法
throw new ExceptionType("异常信息");
4.2 示例
public class ThrowTest {public static void main(String[] args) {try {throw new IOException("手动抛出异常");} catch (IOException e) {System.out.println("捕获到异常:" + e.getMessage());}}
}
5. 用户自定义异常类
5.1 自定义异常类
- 继承:通常继承
RuntimeException
或Exception
。 - 构造器:提供多个构造器,方便传递异常信息。
5.2 示例
class MyException extends Exception {private int idnumber;public MyException(String message, int id) {super(message);this.idnumber = id;}public int getId() {return idnumber;}
}public class MyExpTest {public static void main(String[] args) {try {regist(-1); } catch (MyException e) {System.out.println("登记失败,出错种类:" + e.getId());}}public static void regist(int num) throws MyException {if (num < 0) {throw new MyException("人数为负值,不合理", 3);} else {System.out.println("登记人数:" + num);}}
}
5.3 异常处理关键字
关键字 | 描述 |
---|
try | 捕获异常 |
catch | 处理异常 |
finally | 无论是否发生异常,都会执行 |
throw | 手动抛出异常 |
throws | 声明方法可能抛出的异常 |
5.4 异常处理关键字对比表
关键字 | 作用域 | 使用场景 | 示例代码片段 |
---|
try | 代码块 | 包裹可能抛出异常的代码 | try { ... } |
catch | 紧随try块 | 捕获并处理特定类型异常 | catch (IOException e) { ... } |
finally | 最后执行块 | 释放资源/清理操作 | finally { fis.close(); } |
throw | 方法内部 | 主动抛出异常对象 | throw new Exception("msg"); |
throws | 方法声明处 | 声明可能抛出的异常类型 | void read() throws IOException |
5.5 异常处理流程
try {// 可能抛出异常的代码
} catch (Exception e) {// 处理异常
} finally {// 无论是否发生异常,都会执行
}
6. 异常处理最佳实践
6.1 处理策略对比
场景 | try-catch处理 | throws声明 |
---|
当前方法能处理异常 | ✅ 优先使用 | ❌ 不适用 |
需要资源释放 | ✅ 必须配合finally使用 | ❌ 无法保证资源释放 |
方法不具备处理能力 | ❌ 不应捕获 | ✅ 声明throws |
框架底层代码 | ❌ 避免过度捕获 | ✅ 向上传递 |
6.2 自定义异常设计原则
7. 综合应用示例
7.1 文件读取标准模板
public class FileProcessor {public void processFile(String path) {FileInputStream fis = null;try {fis = new FileInputStream(path);} catch (FileNotFoundException e) {System.out.println("文件未找到: " + e.getMessage());} catch (IOException e) {System.out.println("IO异常: " + e.getLocalizedMessage());} finally {if (fis != null) {try {fis.close();} catch (IOException e) {System.out.println("关闭流失败: " + e.getMessage());}}}}
}
7.2 异常转译模式
public class Service {public void businessOperation() throws BusinessException {try {new Dao().dataAccess();} catch (SQLException e) {throw new BusinessException("业务操作失败", e);}}
}class BusinessException extends Exception {public BusinessException(String msg, Throwable cause) {super(msg, cause);}
}
8. 异常处理性能优化
8.1 异常使用禁忌表
错误用法 | 问题描述 | 改进方案 |
---|
空的catch块 | 异常被静默吞噬 | 至少记录日志 |
捕获Throwable | 可能捕获Error导致程序无法终止 | 明确捕获具体异常类型 |
频繁抛出异常控制流程 | 性能低下(比普通返回慢100倍) | 使用状态码或返回值控制流程 |
忽略资源关闭 | 导致资源泄漏 | 使用try-with-resources语法 |
8.2 try-with-resources示例(Java7+)
public class ResourceExample {public static void main(String[] args) {try (FileInputStream fis = new FileInputStream("test.txt");BufferedReader br = new BufferedReader(new InputStreamReader(fis))) {String line;while ((line = br.readLine()) != null) {System.out.println(line);}} catch (IOException e) {System.out.println("自动关闭资源,异常信息: " + e.getMessage());}}
}