一、什么是异常?
想象一下,你在路上开车,突然发动机故障灯亮了。这时候你知道可能出了问题,需要检查一下。程序也是如此——在运行过程中,也会遇到各种"突发状况",我们称之为异常。
比如我们经常遇到的:
//算术异常:除数为零
System.out.println(10 / 0);
//数组越界异常
int[] arr = {1, 2, 3};
System.out.println(arr[100]);
//空指针异常
String str = null;
System.out.println(str.length());
Java 为各种异常情况提供了对应的异常类,帮助我们精准地定位和处理问题。
二、异常的体系结构
Java 的异常体系结构清晰且层次分明:
Throwable
├── Error(不可处理,如内存溢出)
└── Exception(可处理)
├── IOException(编译时异常)
└── RuntimeException(运行时异常)
-
Error:指严重问题,如内存溢出(OutOfMemoryError),通常无法处理
-
Exception:程序员可以通过代码处理的异常,是我们关注的重点
三、异常的分类
3.1 编译时异常
在编译期间就能被发现的异常,必须处理否则无法通过编译。
//必须处理 CloneNotSupportedException
@Override
public Person clone() throws CloneNotSupportedException {
return (Person)super.clone();
}
3.2 运行时异常
程序运行期间发生的异常,如空指针、数组越界等。
四、异常处理的两种哲学
4.1 LBYL(Look Before You Leap)
事前检查,防患于未然
if (file.exists()) {
// 读取文件
} else {
// 处理文件不存在的情况
}
4.2 EAFP(It's Easier to Ask Forgiveness than Permission)
先操作,遇到问题再处理
try {
//读取文件
} catch (FileNotFoundException e) {
//处理文件不存在的情况
}
Java 主要采用 EAFP 风格,通过五个关键字实现异常处理:throw、try、catch、finally、throws。
五、异常的处理方式
5.1 抛出异常(throw)
public static int getElement(int[] array, int index) {
if (array == null) {
throw new NullPointerException("数组不能为null");
}
if (index < 0 || index >= array.length) {
throw new ArrayIndexOutOfBoundsException("索引越界");
}
return array[index];
}
5.2 声明异常(throws)
public void readFile(String filename) throws FileNotFoundException {
if (!filename.equals("config.ini")) {
throw new FileNotFoundException("配置文件不存在");
}
//读取文件
}
5.3 捕获异常(try-catch)
try {
//可能抛出异常的代码
config.openConfig("config.txt");
} catch (FileNotFoundException e) {
//处理异常
System.out.println("文件未找到: " + e.getMessage());
e.printStackTrace();
} finally {
//无论是否发生异常都会执行
System.out.println("资源清理操作");
}
六、异常处理流程
当异常发生时,JVM 会沿着方法调用栈向上寻找合适的异常处理器。如果一直找不到,最终会交给 JVM 处理,导致程序终止。
public static void main(String[] args) {
try {
func();
} catch (Exception e) {
e.printStackTrace(); //打印调用栈信息
}
}
public static void func() {
int[] arr = {1, 2, 3};
System.out.println(arr[100]); //这里发生异常
}
七、自定义异常
Java 允许我们创建自己的异常类来表示特定的业务异常。
//自定义用户名异常
class UserNameException extends Exception {
public UserNameException(String message) {
super(message);
}
}
//自定义密码异常
class PasswordException extends Exception {
public PasswordException(String message) {
super(message);
}
}
//使用自定义异常
public void login(String username, String password)
throws UserNameException, PasswordException {
if (!isValidUsername(username)) {
throw new UserNameException("用户名错误");
}
if (!isValidPassword(password)) {
throw new PasswordException("密码错误");
}
//登录成功
}
八、重要注意事项
-
try-catch-finally 中,finally 块总是执行,常用于资源清理
-
捕获异常时,子类异常应该放在父类异常之前
-
不要过度使用异常处理,正常流程控制应该用条件语句
-
异常处理应该提供有意义的错误信息
-
日志记录是异常处理的重要组成部分
总结
异常处理是 Java 编程中不可或缺的一部分。良好的异常处理可以使程序更加健壮和易于维护。记住:不要忽视异常,也不要过度使用异常。根据具体情况选择合适的处理方式,让程序在遇到问题时能够优雅地降级或恢复。希望本文能帮助你更好地理解和使用 Java 异常处理机制!
1万+

被折叠的 条评论
为什么被折叠?



