一句话总结
Error 和 Exception 都是 Throwable 的子类,但它们代表了两种完全不同性质的问题:

- Error (错误):指程序无法处理的严重问题,通常是 JVM 层面的问题,比如系统崩溃、虚拟机错误、内存溢出等,这类问题一旦发生,JVM 一般会选择终止线程。我们通常不、也不应该尝试去捕获和处理 Error。
- Exception (异常):指程序可以处理的异常情况,是程序在运行时发生的事件,它会中断正常的指令流,文件找不到、网络连接中断、试图除以零等,这类问题是可以被捕获并处理的,我们应该编写代码来预见和处理这些异常。
类继承体系图
理解它们在 Java 类库中的位置是关键。
java.lang.Object
|
+-- java.lang.Throwable
|
+-- java.lang.Error (错误)
| |
| +-- VirtualMachineError ( OutOfMemoryError)
| +-- ThreadDeath
| +-- ... (其他JVM错误)
|
+-- java.lang.Exception (异常)
|
+-- RuntimeException (运行时异常 / 非受检异常)
| |
| +-- NullPointerException
| +-- IllegalArgumentException
| +-- IndexOutOfBoundsException
| +-- ... (其他编程错误或逻辑漏洞导致的异常)
|
+-- IOException and its subclasses (受检异常)
| |
| +-- FileNotFoundException
| +-- EOFException
| +-- ... (通常由I/O操作失败引起的异常)
Error (错误) 详细说明
Error 表示仅靠程序本身无法恢复的严重问题,它描述的是合理的应用程序不应该试图捕获的严重问题。
主要特点:
- 严重性:通常是灾难性的,如 JVM 耗尽了所有可用内存(
OutOfMemoryError),或者发生了内部错误(VirtualMachineError)。 - 可恢复性:几乎无法恢复,即使捕获了,程序也无法继续正常运行。
- 处理方式:不应该被捕获。
Error发生,最佳策略是让程序终止,并记录错误日志,然后由系统管理员或开发者来修复根本原因(比如增加内存、修复 JVM Bug 等)。 - 来源:主要来自 JVM 运行时环境。
常见的 Error 示例:
-
OutOfMemoryError: 当 JVM 没有足够内存来为新对象分配空间,并且垃圾回收器也无法释放更多内存时抛出。// 示例代码会抛出 OutOfMemoryError public class OOMErrorDemo { public static void main(String[] args) { List<byte[]> list = new ArrayList<>(); try { while (true) { // 不断分配大块内存,最终会耗尽 JVM 堆内存 list.add(new byte[10 * 1024 * 1024]); // 10MB } } catch (OutOfMemoryError e) { // 捕获了,但程序状态已经不可用,通常无法继续 System.err.println("Caught OutOfMemoryError, but program is likely in an unstable state."); e.printStackTrace(); } } } -
StackOverflowError: 当应用程序递归调用过深,超出了 JVM 栈的深度限制时抛出。
(图片来源网络,侵删)// 示例代码会抛出 StackOverflowError public class StackOverflowErrorDemo { public static void recursiveCall() { recursiveCall(); // 无限递归 } public static void main(String[] args) { try { recursiveCall(); } catch (StackOverflowError e) { System.err.println("Caught StackOverflowError."); e.printStackTrace(); } } } -
NoClassDefFoundError: 当 JVM 试图加载一个类时,但在运行时找不到该类的定义文件(.class 文件)时抛出。
Exception (异常) 详细说明
Exception 是程序本身可以处理的异常,它是我们日常编码中需要重点关注和处理的部分。
Exception 又分为两大类:受检异常 和 非受检异常。
A. 受检异常
主要特点:
- 编译器检查:Java 编译器会强制要求你处理这类异常,要么使用
try-catch块捕获它,要么在方法签名中使用throws关键字声明它可能抛出该异常。 - 来源:通常由外部因素引起,比如文件不存在、网络中断、数据库连接失败等,这些是程序可以预见但无法完全避免的。
- 处理方式:必须处理,这是 Java 强制程序员考虑“失败”场景的机制,有助于编写更健壮的代码。
常见的受检异常示例:
IOException: 处理 I/O 操作失败。FileNotFoundException: 试图打开一个不存在的文件。EOFException: 在读取文件或流时,意外到达了文件末尾。
SQLException: 与数据库交互时发生错误。ClassNotFoundException: 当应用程序试图通过其字符串名称加载类时,找不到该类的定义。
代码示例(必须处理):
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class CheckedExceptionDemo {
public static void main(String[] args) {
// 1. 使用 try-catch 捕获
try {
FileInputStream fis = new FileInputStream("non_existent_file.txt");
// ... 读取文件
} catch (FileNotFoundException e) {
System.err.println("文件未找到,请检查路径: " + e.getMessage());
// 这里可以进行一些恢复操作,比如提示用户重新输入文件名
}
// 2. 在方法签名中使用 throws 声明,并将处理责任交给调用者
try {
readFile();
} catch (IOException e) {
System.err.println("调用 readFile 方法时发生I/O错误: " + e.getMessage());
}
}
public static void readFile() throws IOException, FileNotFoundException {
// 这个方法不处理异常,而是把它“抛”给调用者
FileInputStream fis = new FileInputStream("some_file.txt");
// ...
}
}
B. 非受检异常
主要特点:
- 编译器不检查:编译器不会强制你处理这类异常,你可以选择捕获,也可以不捕获。
- 来源:通常是由程序员的逻辑错误或API使用不当引起的,比如试图在一个空对象上调用方法、访问数组越界等。
- 处理方式:应该修复代码,而不是捕获异常,捕获非受检异常通常意味着你隐藏了一个本应在开发阶段就发现的 Bug。
常见的非受检异常示例:
RuntimeException及其子类:NullPointerException: 当你试图在null对象上调用方法或访问其字段时抛出。String str = null; System.out.println(str.length()); // 抛出 NullPointerException
IllegalArgumentException: 当向方法传递了一个不合法或不适当的参数时抛出。Thread t = new Thread(null, new Runnable() { ... }, "MyThread", -1); // 负的栈大小,抛出 IllegalArgumentExceptionIndexOutOfBoundsException: 当访问数组、列表或字符串的非法索引时抛出。int[] arr = new int[5]; System.out.println(arr[10]); // 抛出 ArrayIndexOutOfBoundsException
ClassCastException: 当试图将一个对象强制转换为它不是实例的子类时抛出。Object obj = new Integer(10); String str = (String) obj; // 抛出 ClassCastException
ArithmeticException: 算术运算错误,如除以零。int a = 10; int b = 0; System.out.println(a / b); // 抛出 ArithmeticException
Error vs. Exception 对比总结
| 特性 | Error (错误) |
Exception (异常) |
|---|---|---|
| 父类 | java.lang.Error |
java.lang.Exception |
| 性质 | JVM 或硬件层面的严重问题,程序无法控制 | 程序运行时的异常情况,程序可以预见和处理 |
| 可恢复性 | 通常不可恢复,程序会终止 | 通常可以恢复,通过捕获异常并采取相应措施 |
| 处理方式 | 不应该被捕获,应交 |

