Java学习第三十二部分——异常
目录
二. 层次结构
三. 常见类型
四. 基本结构
(1)try-catch-finally 块
(2)抛出异常
(3)声明异常
(4)自定义异常
(5)异常链
(6)多异常捕获
(7)资源清理
五. 处理原则
六. 使用场景
七. 最佳实践
八.项目实战——文件处理系统
1.打开idea,创建Java项目,构建系统选“Maven”
2. 按下图所示创建类,包和txt文件(新建——文件中直接加“.txt”后缀即可创建)
3. 三个文件相关类代码内容如下
4.Main类代码如下
5.可直接运行Main类,也可适当改动一些txt文件,理解这个项目作用
6.代码解释
九.附言
在Java中,异常是程序在执行过程中发生的问题,它会打断正常的指令流。Java提供了一套对应的异常处理机制,使程序能够捕获并处理这些异常,从而增强程序的健壮性和容错性。
二. 层次结构
Java中的异常都继承自Throwable类,它有两个主要的子类:Error和Exception。
- **Error**:表示严重的错误,通常是程序无法处理的,如`OutOfMemoryError`、`StackOverflowError`等。程序通常不处理这类错误。
- **Exception**:表示程序可以处理的异常。它分为两大类:
- **受检异常(Checked Exception)**:编译器要求必须处理的异常,如`IOException`、`SQLException`等。
- **非受检异常(Unchecked Exception)**:编译器不强制要求处理的异常,包括`RuntimeException`及其子类,如`NullPointerException`、`IndexOutOfBoundsException`等。
三. 常见类型
| 异常类型 | 描述 | 发生场景 |
|---------|------|----------|
| `NullPointerException` | 空指针异常 | 调用 null 对象的方法 |
| `ArrayIndexOutOfBoundsException` | 数组越界 | 访问无效数组索引 |
| `ClassCastException` | 类型转换错误 | 不兼容的类型转换 |
| `IllegalArgumentException` | 非法参数 | 方法接收到无效参数 |
| `NumberFormatException` | 数字格式错误 | 字符串转数字失败 |
| `FileNotFoundException` | 文件未找到 | 访问不存在的文件 |
| `IOException` | 输入输出异常 | 文件读写错误 |
| `SQLException` | 数据库操作异常 | 数据库访问错误 |
四. 基本结构
(1)try-catch-finally 块
基本的异常类结构。
public class Main {public static void main(String[] args) {try {int result = 10 / 0; // 会抛出ArithmeticException} catch (ArithmeticException e) {System.out.println("Caught an ArithmeticException: " + e.getMessage());} finally {System.out.println("This is the finally block.");}}
}
(2)抛出异常
使用`throw`关键字可以手动抛出一个异常。
public class Main {public static void main(String[] args) {try {throw new IllegalArgumentException("Invalid argument");} catch (IllegalArgumentException e) {System.out.println("Caught an IllegalArgumentException: " + e.getMessage());}}
}
(3)声明异常
使用`throws`关键字可以声明一个方法可能会抛出的异常。
import java.io.FileInputStream;
import java.io.FileNotFoundException;public class Main {public static void main(String[] args) {try {readFile("nonexistent.txt");} catch (FileNotFoundException e) {System.out.println("File not found: " + e.getMessage());}}public static void readFile(String fileName) throws FileNotFoundException {FileInputStream file = new FileInputStream(fileName);}
}
(4)自定义异常
自定义异常是通过继承`Exception`类或其子类来创建的。
// 自定义异常类
class MyCustomException extends Exception {public MyCustomException(String message) {super(message);}
}public class Main {public static void main(String[] args) {try {throw new MyCustomException("This is a custom exception");} catch (MyCustomException e) {System.out.println("Caught a MyCustomException: " + e.getMessage());} finally {System.out.println("This is the finally block.");}}
}
(5)异常链
异常链是指一个异常被包装在另一个异常中,这样可以保留原始异常的信息。
public class Main {public static void main(String[] args) {try {try {throw new IllegalArgumentException("Invalid argument");} catch (IllegalArgumentException e) {throw new RuntimeException("An error occurred", e);}} catch (RuntimeException e) {System.out.println("Caught a RuntimeException: " + e.getMessage());System.out.println("Original exception: " + e.getCause());} finally {System.out.println("This is the finally block.");}}
}
(6)多异常捕获
可以使用`|`运算符来捕获多个异常类型。
public class Main {public static void main(String[] args) {try {int result = 10 / 0; // 会抛出ArithmeticException} catch (ArithmeticException | NullPointerException e) {System.out.println("Caught an exception: " + e.getMessage());} finally {System.out.println("This is the finally block.");}}
}
(7)资源清理
在`finally`块中释放资源,如关闭文件、数据库连接等。
import java.io.FileInputStream;
import java.io.FileNotFoundException;public class Main {public static void main(String[] args) {FileInputStream file = null;try {file = new FileInputStream("nonexistent.txt");} catch (FileNotFoundException e) {System.out.println("File not found: " + e.getMessage());} finally {if (file != null) {try {file.close();} catch (Exception e) {System.out.println("Error closing file: " + e.getMessage());}}System.out.println("This is the finally block.");}}
}
五. 处理原则
1. **早抛出**:在发现问题时立即抛出异常
2. **晚捕获**:在能处理异常的地方捕获
3. **具体化**:使用最具体的异常类型
4. **文档化**:使用 Javadoc 记录异常行为
5. **资源安全**:确保资源正确释放
六. 使用场景
1. **受检异常**:可恢复的错误(如文件不存在、网络中断)
2. **非受检异常**:编程错误(如空指针、无效参数)
3. **自定义异常**:特定领域错误(如业务规则违规)
4. **错误**:严重系统问题(不捕获,应修复)
七. 最佳实践
- **捕获具体的异常**:尽量捕获具体的异常类型,而不是使用通用的`Exception`。
- **不要忽略异常**:捕获到异常后,应该进行适当的处理,而不是留空。
- **使用finally块释放资源**:在`finally`块中释放资源,如关闭文件、数据库连接等。
- **不要过度使用异常**:异常处理不应该用于正常的控制流程,只用于处理异常情况。
八.项目实战——文件处理系统
1.打开idea,创建Java项目,构建系统选“Maven”
2. 按下图所示创建类,包和txt文件(新建——文件中直接加“.txt”后缀即可创建)
3. 三个文件相关类代码内容如下
package com.fileprocessor;import java.io.*;public class FileReaderUtil {// 读取文件内容为字符串public static String readFileAsString(String filePath) throws IOException {File file = new File(filePath);if (!file.exists()) {throw new FileNotFoundException("文件不存在: " + filePath);}if (file.length() == 0) {throw new IOException("文件内容为空: " + filePath);}try (BufferedReader reader = new BufferedReader(new FileReader(file))) {StringBuilder content = new StringBuilder();String line;while ((line = reader.readLine()) != null) {content.append(line).append("\n");}return content.toString();}}
}
package com.fileprocessor;import java.util.Arrays;public class FileAnalysis {// 统计文件中的数字平均值public static double calculateAverage(String content) {if (content == null || content.trim().isEmpty()) {throw new IllegalArgumentException("文件内容无效");}String[] parts = content.split("\\s+");double sum = 0;int count = 0;for (String part : parts) {try {double number = Double.parseDouble(part);sum += number;count++;} catch (NumberFormatException e) {System.err.println("警告: 跳过非数字内容 - " + part);}}if (count == 0) {throw new ArithmeticException("文件中没有有效的数字");}return sum / count;}// 查找最大数字public static double findMaxNumber(String content) {return Arrays.stream(content.split("\\s+")).filter(s -> s.matches("-?\\d+(\\.\\d+)?")).mapToDouble(Double::parseDouble).max().orElseThrow(() -> new RuntimeException("无法找到最大值"));}
}
package com.fileprocessor;import java.io.IOException;public class FileProcessor {// 处理文件并返回分析结果public static String processFile(String filePath) {try {String content = FileReaderUtil.readFileAsString(filePath);double average = FileAnalysis.calculateAverage(content);double max = FileAnalysis.findMaxNumber(content);return String.format("文件分析结果:\n- 平均值: %.2f\n- 最大值: %.2f", average, max);} catch (IOException e) {return "文件读取错误: " + e.getMessage();} catch (IllegalArgumentException e) {return "内容格式错误: " + e.getMessage();} catch (ArithmeticException e) {return "计算错误: " + e.getMessage();} finally {System.out.println("文件处理完成: " + filePath);}}// 处理多个文件public static void processMultipleFiles(String[] filePaths) {for (String path : filePaths) {try {System.out.println("\n处理文件: " + path);System.out.println(processFile(path));} catch (Exception e) {System.err.println("处理失败: " + e.getMessage());}}}
}
4.Main类代码如下
package com.fileprocessor;public class Main {public static void main(String[] args) {// 有效文件String validFile = "src/main/resources/data.txt";// 无效文件String nonExistentFile = "src/main/resources/missing.txt";String emptyFile = "src/main/resources/empty.txt";String invalidContentFile = "src/main/resources/invalid.txt";// 处理单个文件System.out.println("=== 有效文件处理 ===");System.out.println(FileProcessor.processFile(validFile));System.out.println("\n=== 不存在文件处理 ===");System.out.println(FileProcessor.processFile(nonExistentFile));System.out.println("\n=== 空文件处理 ===");System.out.println(FileProcessor.processFile(emptyFile));System.out.println("\n=== 无效内容文件处理 ===");System.out.println(FileProcessor.processFile(invalidContentFile));// 批量处理文件System.out.println("\n=== 批量文件处理 ===");String[] files = {validFile,nonExistentFile,emptyFile,invalidContentFile};FileProcessor.processMultipleFiles(files);}
}
5.可直接运行Main类,也可适当改动一些txt文件,理解这个项目作用
这里小编为date.txt文件添加了这些数字10 20 30 42 5 15 25运行结果如下
6.代码解释
(1)项目概述
这是一个Java文件处理系统,主要功能是读取文本文件内容,分析其中的数字数据,计算平均值和最大值。项目展示了Java异常处理在实际应用中的使用方式。
(2)核心功能
1. **文件读取**:读取文本文件内容
2. **数据分析**:计算文件中数字的平均值和最大值
3. **异常处理**:处理各种文件处理过程中可能出现的错误情况
(3)主要类及其功能
1. FileReaderUtil(文件读取工具)
- **功能**:读取文本文件内容
- **关键点**:
- 检查文件是否存在
- 检查文件是否为空
- 读取文件内容并返回为字符串
- **可能抛出异常**:
- `FileNotFoundException`(文件不存在)
- `IOException`(文件为空或读取错误)
2. FileAnalysis(文件分析类)
- **功能**:分析文件内容中的数字
- **关键点**:
- 将文件内容分割成多个部分
- 尝试将每个部分解析为数字
- 计算所有数字的平均值和最大值
- **可能抛出异常**:
- `IllegalArgumentException`(内容无效)
- `ArithmeticException`(没有有效数字)
3. FileProcessor(文件处理器)
- **功能**:协调文件读取和分析过程
- **关键点**:
- 调用FileReaderUtil读取文件
- 调用FileAnalysis分析内容
- 捕获并处理各种异常
- 返回最终结果或错误信息
- **处理流程**:
1. 尝试读取文件
2. 尝试分析内容
3. 捕获可能的异常
4. 无论成功与否,都执行清理工作
4. Main(主程序)
- **功能**:演示系统的使用
- **关键点**:
- 创建不同测试场景:
- 有效文件(包含数字)
- 不存在文件
- 空文件
- 无效内容文件(包含非数字)
- 分别处理单个文件和批量文件
- 展示各种情况下的处理结果
(4)异常处理展示
项目演示了如何处理多种异常情况:
1. **文件不存在** → 显示"文件不存在"错误
2. **文件为空** → 显示"文件内容为空"错误
3. **内容无效** → 显示"内容格式错误"
4. **没有有效数字** → 显示"文件中没有有效的数字"
5. **批量处理中的错误隔离** → 一个文件出错不影响其他文件处理
(5)运行流程
1. 主程序创建不同测试文件路径
2. 调用文件处理器处理每个文件
3. 文件处理器尝试读取文件内容
4. 文件分析器处理内容并计算平均值和最大值
5. 结果或错误信息返回给主程序
6. 主程序显示最终结果
(6)典型输出
- **有效文件**:显示平均值和最大值
- **不存在文件**:显示"文件不存在"错误
- **空文件**:显示"文件内容为空"错误
- **无效内容文件**:显示警告并跳过非数字内容
(7)项目价值
1. 展示了Java异常处理的完整流程
2. 演示了如何优雅地处理文件操作中的各种错误
3. 体现了资源管理的最佳实践(finally块)
4. 提供了批量处理中的错误隔离机制
九.附言
注解在前面部分Java学习第十一部分——注解-CSDN博客,因此不再详细阐述。