目录
一、异常概述
1.异常定义
2.异常层次结构
3.异常类型划分
4.异常触发机制分析
二、异常处理方案
1.throw关键字使用
2.Objects工具类应用
3.throws声明规范
4.try-catch捕获机制
5.finally块特性
6.处理规范要点
(1)独立处理不同异常
(2)统一捕获分类处理
(3)批量捕获统一处理
三、用户自定义异常
1.基本概念
2.实践案例
一、异常概述
1.异常定义
异常指程序运行时的非预期状况。类比医疗诊断,当医生告知某指标异常,意味着该指标偏离正常范围。在编程领域:
程序异常:指代码执行过程中发生的意外事件,可能导致虚拟机非正常终止。Java等面向对象语言将异常封装为类对象,异常触发实质是异常对象的实例化与抛出过程,采用中断机制进行处理。
2.异常层次结构
异常机制的核心价值在于问题定位,其基类为java.lang.Throwable
,衍生出两大子类:java.lang.Error
与java.lang.Exception
,通常讨论的异常特指后者。
Throwable分类:
a. 系统级错误:指不可恢复的严重故障(如内存溢出),需提前预防
b. 程序异常:可通过代码修正的常规问题(如格式错误),必须处理
常用方法:
a.printStackTrace()
:输出完整堆栈轨迹
b.getMessage()
:获取异常描述信息
c.toString()
:返回异常类型及描述(较少使用)
3.异常类型划分
重点关注Exception及其子类,这类异常需要开发者主动处理。
异常分类标准:
a. 编译时异常:代码编译阶段强制检查的异常(如文件不存在异常)
b. 运行时异常:执行阶段才会暴露的问题(如除零错误)
4.异常触发机制分析
以下示例演示数组越界异常(ArrayIndexOutOfBoundsException)的产生过程:
工具类实现:
public class ArrayUtil {
// 根据索引获取数组元素
public static int fetchElement(int[] data, int pos) {
int value = data[pos];
return value;
}
}
测试用例:
public class ExceptionCase {
public static void main(String[] args) {
int[] dataset = { 34, 12, 67 };
int result = ArrayUtil.fetchElement(dataset, 4);
System.out.println("结果值=" + result);
System.out.println("程序结束");
}
}
执行过程示意图:
二、异常处理方案
Java提供五大处理关键词:try、catch、finally、throw、throws。
1.throw关键字应用
开发时应充分考虑参数合法性。当检测到非法参数时,可通过throw主动抛出异常对象通知调用方。
实现步骤:
a. 实例化异常对象
b. 向调用链上层抛出
语法规范:
throw new 异常类型(描述信息);
示例:
throw new NullPointerException("检测到空数组");
throw new ArrayIndexOutOfBoundsException("索引超出有效范围");
完整案例:
public class Demo {
public static void main(String[] args) {
int[] numbers = {2,4,52,2};
int position = 4;
int target = locateElement(numbers, position);
System.out.println(target);
System.out.println("执行完成");
}
public static int locateElement(int[] data, int pos){
if(pos > data.length-1){
throw new ArrayIndexOutOfBoundsException("非法索引位置");
}
return data[pos];
}
}
提示:使用throw抛出异常后,当前方法执行将立即终止。
2.Objects工具类校验
requireNonNull
方法可快速验证对象非空:
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
// 实际应用
Objects.requireNonNull(param, "参数不能为null");
3.throws声明规范
当方法内部可能抛出检查性异常且未处理时,必须使用throws声明异常类型。
语法结构:
[修饰符] 返回值 方法名(参数列表) throws 异常类型1, 异常类型2…{ }
示例:
public class FileOperator {
public static void main(String[] args) throws IOException {
loadFile("config.ini");
}
public static void loadFile(String filename) throws FileNotFoundException {
if (!filename.endsWith(".ini")) {
throw new FileNotFoundException("无效文件格式");
}
}
}
多异常声明:
public static void processFile(String path)
throws FileNotFoundException, IOException {
// 方法实现
}
4.try-catch捕获机制
异常捕获基本结构:
try {
// 可能抛出异常的代码
} catch(异常类型 变量名) {
// 异常处理逻辑
}
实践案例:
public class ExceptionHandler {
public static void main(String[] args) {
try {
readDocument("temp.doc");
} catch (FileNotFoundException e) {
System.err.println("文件读取失败:" + e.getMessage());
}
System.out.println("流程继续");
}
public static void readDocument(String file) throws FileNotFoundException {
if (!file.endsWith(".txt")) {
throw new FileNotFoundException("仅支持文本文件");
}
}
}
异常信息获取方法:
– getMessage()
:获取异常描述
– toString()
:返回完整异常信息
– printStackTrace()
:打印调用堆栈
5.finally块特性
无论是否发生异常,finally块中的代码必定执行,常用于资源释放。
典型应用:
public class ResourceManager {
public static void main(String[] args) {
try {
accessResource("data.db");
} catch (RuntimeException e) {
throw new RuntimeException(e);
} finally {
System.out.println("资源清理完成");
}
}
public static void accessResource(String res) throws FileNotFoundException {
// 资源访问逻辑
}
}
注意:仅当调用System.exit()或虚拟机崩溃时,finally块才不会执行。
6.处理规范要点
(1)独立异常处理
public class MultiHandler {
public static void main(String[] args) {
// 独立处理数组越界
try {
int[] values = {1,2,3};
System.out.println(values[3]);
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}
// 独立处理集合越界
try {
List<Integer> nums = List.of(1,2,3);
System.out.println(nums.get(3));
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
}
(2)统一捕获分类处理
try {
int[] data = {1,2,3};
System.out.println(data[3]);
List<Integer> seq = List.of(1,2,3);
System.out.println(seq.get(3));
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界");
} catch (IndexOutOfBoundsException e) {
System.out.println("索引越界");
}
(3)批量捕获处理
try {
// 可能抛出多种异常的代码
} catch (Exception e) {
// 统一处理逻辑
}
重要原则:
– 子类异常需先于父类异常捕获
– finally块避免使用return语句
– 子类方法异常声明不能超出父类范围
三、用户自定义异常
1.基本概念
开发者可创建符合业务需求的异常类,例如注册场景的专属异常。
创建规范:
– 编译时异常:继承Exception类
– 运行时异常:继承RuntimeException类
2.实践案例
实现用户注册校验,当用户名存在时抛出自定义异常:
异常类定义:
public class DuplicateUserException extends Exception {
public DuplicateUserException() {}
public DuplicateUserException(String msg) {
super(msg);
}
}
业务逻辑实现:
public class UserService {
private static String[] existingUsers = {"admin","guest","test"};
public static void main(String[] args) {
try {
validateUsername("newUser");
System.out.println("注册成功");
} catch (DuplicateUserException e) {
e.printStackTrace();
}
}
public static boolean validateUsername(String name)
throws DuplicateUserException {
for (String user : existingUsers) {
if(user.equals(name)) {
throw new DuplicateUserException("用户名"+name+"已存在");
}
}
return true;
}
}