欢迎访问作者Github:Joeysoda/Github_java: Study java
在 Java 中,异常是程序在执行过程中发生的非正常行为。理解并正确处理异常是编写健壮、可靠代码的关键。下面我们将详细讲解 Java 的异常处理机制,涵盖异常体系结构、异常的分类、异常的处理流程、以及关键字 try、catch、throw、throws、finally 的使用。
目录
1. 异常的体系结构
1.1 Throwable 类
1.2 Error 类
1.3 Exception 类
1.4 异常的分类
2. 异常的处理
2.1 防御性编程策略
2.2 异常的抛出
2.3 异常的捕获
2.3.1 throws 声明
2.3.2 try-catch 捕获
2.3.3 finally 块
面试题:finally 和 try-catch-finally 后的代码都会执行,为什么还要有 finally?
3. 面试题解析
3.1 throw 和 throws 的区别
3.2 finally 中的语句一定会执行吗?
4. 自定义异常类
自定义异常注意事项:
总结:异常的处理流程
1. 异常的体系结构
1.1 Throwable 类
Java 中所有异常类都继承自 java.lang.Throwable,它是 Java 中异常体系的根类。Throwable 有两个直接子类:
Error:表示系统级错误,是 JVM 无法处理的严重问题,例如StackOverflowError、OutOfMemoryError。这些错误通常由 JVM 抛出,程序无法恢复或处理这些错误。Exception:表示程序运行过程中可以预期并可以通过代码处理的异常,例如IOException、NullPointerException等。
1.2 Error 类
Error类代表了 JVM 运行过程中出现的严重错误,程序员通常不需要或无法处理这些错误,属于系统级错误。- 典型的
Error:StackOverflowError:栈溢出错误。OutOfMemoryError:内存溢出错误。
1.3 Exception 类
Exception类是应用程序可以通过代码进行捕获和处理的异常类。典型的异常包括:ArithmeticException:算术异常(如除以 0)。ArrayIndexOutOfBoundsException:数组越界异常。NullPointerException:空指针异常。
1.4 异常的分类
-
编译时异常(Checked Exception):
- 编译时异常是在代码编译阶段需要强制处理的异常。如果程序员没有正确处理这些异常,编译器会报错,无法通过编译。常见的编译时异常有
IOException、SQLException。 - 处理方式:需要通过
try-catch或throws来处理。
- 编译时异常是在代码编译阶段需要强制处理的异常。如果程序员没有正确处理这些异常,编译器会报错,无法通过编译。常见的编译时异常有
-
运行时异常(Unchecked Exception/RuntimeException):
- 运行时异常是在程序运行时发生的异常,通常是由于编程错误引起的。这类异常不要求在编译时必须处理,程序可以选择不捕获此类异常,直接由 JVM 处理。常见的运行时异常包括
NullPointerException、ArrayIndexOutOfBoundsException。 - 处理方式:可以不用强制处理,但建议通过良好的编程习惯来避免这些错误。
- 运行时异常是在程序运行时发生的异常,通常是由于编程错误引起的。这类异常不要求在编译时必须处理,程序可以选择不捕获此类异常,直接由 JVM 处理。常见的运行时异常包括
2. 异常的处理
2.1 防御性编程策略
-
LBYL(Look Before You Leap):事前检查。在执行操作之前,检查是否可能发生错误。这是一种预防性编程方法。
- 示例:
if (list != null && list.size() > 0) { System.out.println(list.get(0)); }EAFP(Easier to Ask for Forgiveness than Permission):事后处理。这是一种容错性编程方法,不做过多检查,直接操作,若发生异常再进行处理。
- 示例:
try { System.out.println(list.get(0)); } catch (NullPointerException e) { System.out.println("列表为空!"); }
2.2 异常的抛出
在 Java 中,可以使用 throw 关键字手动抛出异常。常见的异常抛出场景包括参数校验失败等。
注意事项:
throw必须写在方法体内。- 抛出的对象必须是
Throwable的子类(Exception或Error)。 - 如果抛出的是
RuntimeException或其子类,则可以不强制捕获或声明,由 JVM 处理。 - 如果抛出的是编译时异常(
Checked Exception),调用者必须处理,否则无法通过编译。
示例:
public void validateAge(int age) {
if (age < 18) {
throw new IllegalArgumentException("年龄必须大于18");
}
}
2.3 异常的捕获
Java 提供了 try-catch 机制来捕获和处理异常。程序可以在 try 块中编写可能会抛出异常的代码,如果出现异常,就会跳到 catch 块中处理。
2.3.1 throws 声明
当一个方法内部可能抛出异常但不处理时,可以通过 throws 关键字将异常抛给上层调用者。
注意事项:
throws必须跟在方法参数列表之后。throws后的异常必须是Exception或其子类。- 如果方法可能抛出多个异常,必须列出多个异常类型,或声明父类即可。
示例:
public void readFile(String path) throws IOException {
FileReader fileReader = new FileReader(path);
}
2.3.2 try-catch 捕获
try块:包含可能发生异常的代码。catch块:捕获异常并处理。
示例:
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("除数不能为0");
}
2.3.3 finally 块
finally块中的代码无论是否发生异常,都会执行,常用于资源清理操作。- 典型场景:关闭文件、释放数据库连接、关闭网络连接等。
示例:
try {
FileReader file = new FileReader("test.txt");
} catch (FileNotFoundException e) {
System.out.println("文件未找到");
} finally {
System.out.println("最终的资源清理操作");
}
面试题:finally 和 try-catch-finally 后的代码都会执行,为什么还要有 finally?
finally块的意义在于:无论try中是否抛出异常,finally块的代码一定会执行。即使在try或catch块中发生return,finally仍会被执行。try-catch-finally后的代码不一定能执行到,因为如果try或catch中有return或异常终止,后续代码就不会执行,但finally会被执行。
3. 面试题解析
3.1 throw 和 throws 的区别
-
throw:用于显式抛出异常。它是用于在方法内部手动抛出异常的。
throw new IllegalArgumentException("无效参数");
-
throws:用于声明异常,表示当前方法可能抛出异常,需要调用者处理。它用于方法声明中,放在参数列表后面。
3.2 finally 中的语句一定会执行吗?
- 是的,
finally中的代码通常会执行,无论是否抛出了异常。但在某些极端情况下,finally中的代码可能不会执行,例如:- 程序在
try或catch中调用了System.exit()退出 JVM。 - JVM 崩溃,或系统中断。
- 程序所在的线程被强制终止。
- 程序在
4. 自定义异常类
在 Java 中,程序员可以自定义异常类,通常用于封装业务逻辑中的异常信息。自定义异常类通常继承自 Exception 或 RuntimeException。
自定义异常注意事项:
- 继承自
Exception的异常是受检异常,调用者必须处理。 - 继承自
RuntimeException的异常是非受检异常,调用者可以选择不处理,直接交给 JVM 处理。
示例:自定义异常类
class AgeException extends Exception {
public AgeException(String message) {
super(message);
}
}
public void setAge(int age) throws AgeException {
if (age < 18) {
throw new AgeException("年龄不能小于18");
}
}
总结:异常的处理流程
- 程序执行
try块中的代码。 - 如果
try中的代码出现异常,执行会停止,检查catch块中的异常类型是否匹配。- 如果匹配,执行
catch中的代码。 - 如果没有找到匹配的
catch,异常会继续向上层调用者传播。
- 如果匹配,执行
- 无论是否匹配到异常类型,
finally块中的代码都会执行。 - 如果异常没有被任何地方捕获,最终会传递到
main方法,程序会异常终止。
通过正确的异常处理机制,程序可以更好地处理运行时的错误,保持稳定性和健壮性。




![[vue2+axios]下载文件+文件下载为乱码](https://i-blog.csdnimg.cn/direct/6cd822979d7b4eba80f6ae62067bad6c.png)



![[2025]医院健康陪诊系统(源码+定制+服务)](https://i-blog.csdnimg.cn/direct/3c50e9ae67344a8ebceace28e7913ab4.png)










