Java 错误类
最后修改时间:2025 年 4 月 13 日
java.lang.Error 类代表应用程序不应尝试捕获或处理的严重问题。 错误通常源于 Java 虚拟机 (JVM),原因是运行时环境中的根本问题,例如系统资源耗尽或灾难性故障。 与异常不同,错误表示超出应用程序控制范围的情况。
错误是扩展 Throwable 的未经检查的异常。 由于它们表明了合理的应用程序无法从中恢复的严重故障,因此不应通过典型的错误处理机制来捕获或处理它们。 常见的例子包括 OutOfMemoryError(JVM 无法分配内存时发生)和 StackOverflowError(由于过度递归或深度方法调用而发生)。
错误类层次结构
Error 类是 Throwable 的直接子类,与 Exception 并列。 它有几个重要的子类,每个子类代表不同类型的严重故障。
java.lang.Throwable
├── java.lang.Error
│ ├── java.lang.LinkageError
│ ├── java.lang.ThreadDeath
│ ├── java.lang.VirtualMachineError
│ │ ├── java.lang.InternalError
│ │ ├── java.lang.OutOfMemoryError
│ │ ├── java.lang.StackOverflowError
│ │ └── java.lang.UnknownError
│ └── java.lang.AssertionError
└── java.lang.Exception
理解错误类型
- VirtualMachineError: 表示与 JVM 相关的故障,例如
OutOfMemoryError(内存不足)和StackOverflowError(过度递归)。 - LinkageError: 指示类加载和链接问题,例如缺少依赖项或不兼容的二进制版本。
- ThreadDeath: 当使用
Thread.stop()强制停止线程时发生(在现代 Java 中不鼓励使用)。 - AssertionError: 当
assert语句失败时抛出,通常用于调试和验证假设。
Error 类及其子类表示无法优雅处理的问题,这使得它们与常规异常不同。 开发人员应专注于**预防错误**,而不是捕获错误,确保适当的资源管理并避免过度递归或内存密集型操作。
OutOfMemoryError
当 JVM 无法分配对象时,会抛出 OutOfMemoryError,因为内存已耗尽。 这通常发生在堆耗尽时。 垃圾回收器无法释放足够的内存来满足请求。
package com.zetcode;
public class Main {
public static void main(String[] args) {
try {
// Allocate increasingly large arrays until memory is exhausted
int size = Integer.MAX_VALUE;
while (true) {
int[] arr = new int[size];
size *= 2;
}
} catch (OutOfMemoryError e) {
System.out.println("Caught OutOfMemoryError: " + e.getMessage());
}
}
}
此示例通过尝试分配越来越大的数组来故意导致 OutOfMemoryError。 发生错误时,我们会捕获它并打印内存统计信息。 请注意,通常不建议在生产代码中捕获 OutOfMemoryError。
StackOverflowError
当调用堆栈超过其限制时,会发生 StackOverflowError。 这通常发生在无限递归或非常深的递归中,其中每个方法调用都会消耗堆栈空间,直到没有剩余空间为止。
package com.zetcode;
public class Main {
public static void recursiveMethod() {
// Infinite recursion
recursiveMethod();
}
public static void main(String[] args) {
try {
recursiveMethod();
} catch (StackOverflowError e) {
System.out.println("Caught StackOverflowError: " + e.getMessage());
System.out.println("Stack trace length: " + e.getStackTrace().length);
}
}
}
此示例演示了由无限递归引起的 StackOverflowError。 recursiveMethod 无限期地调用自身,直到堆栈空间耗尽。 我们捕获错误并打印有关堆栈跟踪的信息。
NoClassDefFoundError
当 JVM 找不到在编译时可用但在运行时不可用的类定义时,会抛出 NoClassDefFoundError。 这通常发生在 classpath 中缺少必需的类时。
package com.zetcode;
public class Main {
public static void main(String[] args) {
try {
// Attempt to use a class that exists at compile time
// but will be removed before runtime
Class.forName("com.example.NonExistentClass");
} catch (ClassNotFoundException e) {
System.out.println("ClassNotFoundException: " + e.getMessage());
} catch (NoClassDefFoundError e) {
System.out.println("NoClassDefFoundError: " + e.getMessage());
}
}
}
此示例尝试加载运行时不存在的类。 首先,它尝试使用 Class.forName,这会抛出 ClassNotFoundException。 如果该类在编译时可用但在运行时丢失,则会抛出 NoClassDefFoundError。
AssertionError
当断言失败时,会抛出 AssertionError。 断言是在程序执行期间应评估为 true 的布尔表达式。 如果它们评估为 false,则会抛出 AssertionError。
package com.zetcode;
public class Main {
public static void main(String[] args) {
int x = 10;
// Enable assertions (-ea VM option)
assert x > 20 : "x should be greater than 20";
try {
// This will throw AssertionError if assertions are enabled
assert false : "This assertion always fails";
} catch (AssertionError e) {
System.out.println("Caught AssertionError: " + e.getMessage());
}
}
}
此示例演示了 AssertionError。 如果 x 不大于 20,则第一个断言将失败。 第二个断言始终失败并抛出我们捕获的 AssertionError。 请注意,必须使用 -ea VM 选项启用断言。
InternalError
InternalError 指示 JVM 中发生意外的内部错误。 当 JVM 遇到它无法处理的意外情况时,会抛出此错误。 它通常表示 JVM 实现中的错误。
package com.zetcode;
public class Main {
public static void main(String[] args) {
try {
// This might throw InternalError in some JVM implementations
// when encountering certain internal states
throw new InternalError("Simulated JVM internal error");
} catch (InternalError e) {
System.out.println("Caught InternalError: " + e.getMessage());
System.out.println("This indicates a serious JVM problem");
}
}
}
此示例模拟 InternalError。 实际上,当 JVM 遇到意外的内部状态时,它本身会抛出 InternalError。 应用程序通常不应抛出或捕获此错误,因为它表示 JVM 问题。
UnknownError
当 JVM 中发生未知但严重的异常时,会抛出 UnknownError。 这是一个用于不属于其他错误类别的严重问题的包罗万象的错误。
package com.zetcode;
public class Main {
public static void main(String[] args) {
try {
// Simulating an unknown serious error
throw new UnknownError("Unknown serious JVM problem");
} catch (UnknownError e) {
System.out.println("Caught UnknownError: " + e.getMessage());
System.out.println("This indicates an unspecified serious problem");
}
}
}
此示例演示了 UnknownError。 与 InternalError 一样,这通常由 JVM 而不是应用程序代码抛出。 它表示 JVM 中未指定的严重问题,不属于其他错误类别。
LinkageError
当类依赖项存在问题时,会发生 LinkageError。 当类在编译后发生了不兼容的更改,或者类之间存在版本冲突时,可能会发生这种情况。
package com.zetcode;
public class Main {
public static void main(String[] args) {
try {
// Simulating a linkage problem
throw new LinkageError("Class dependency problem");
} catch (LinkageError e) {
System.out.println("Caught LinkageError: " + e.getMessage());
System.out.println("This indicates a class dependency issue");
}
}
}
此示例演示了 LinkageError。 实际上,当类依赖项存在问题时,会发生此错误,例如不兼容的类版本。 该示例演示了如何捕获它,尽管在实际应用程序中很少这样做,因为它表示严重的配置问题。
来源
在本文中,我们通过实际示例介绍了 Java Error 类及其常见的子类。 虽然通常不在普通应用程序代码中捕获错误,但了解它们对于调试严重的 JVM 问题非常重要。
作者
列出所有Java教程。