杰瑞科技汇

Java中Error与Exception有何核心区别?

一句话总结

ErrorException 都是 Throwable 的子类,但它们代表了两种完全不同性质的问题:

Java中Error与Exception有何核心区别?-图1
(图片来源网络,侵删)
  • 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 表示仅靠程序本身无法恢复的严重问题,它描述的是合理的应用程序不应该试图捕获的严重问题

主要特点:

  1. 严重性:通常是灾难性的,如 JVM 耗尽了所有可用内存(OutOfMemoryError),或者发生了内部错误(VirtualMachineError)。
  2. 可恢复性:几乎无法恢复,即使捕获了,程序也无法继续正常运行。
  3. 处理方式不应该被捕获Error 发生,最佳策略是让程序终止,并记录错误日志,然后由系统管理员或开发者来修复根本原因(比如增加内存、修复 JVM Bug 等)。
  4. 来源:主要来自 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 栈的深度限制时抛出。

    Java中Error与Exception有何核心区别?-图2
    (图片来源网络,侵删)
    // 示例代码会抛出 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. 受检异常

主要特点:

  1. 编译器检查:Java 编译器会强制要求你处理这类异常,要么使用 try-catch 块捕获它,要么在方法签名中使用 throws 关键字声明它可能抛出该异常。
  2. 来源:通常由外部因素引起,比如文件不存在、网络中断、数据库连接失败等,这些是程序可以预见但无法完全避免的。
  3. 处理方式必须处理,这是 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. 非受检异常

主要特点:

  1. 编译器不检查:编译器不会强制你处理这类异常,你可以选择捕获,也可以不捕获。
  2. 来源:通常是由程序员的逻辑错误或API使用不当引起的,比如试图在一个空对象上调用方法、访问数组越界等。
  3. 处理方式应该修复代码,而不是捕获异常,捕获非受检异常通常意味着你隐藏了一个本应在开发阶段就发现的 Bug。

常见的非受检异常示例:

  • RuntimeException 及其子类:
    • NullPointerException: 当你试图在 null 对象上调用方法或访问其字段时抛出。
      String str = null;
      System.out.println(str.length()); // 抛出 NullPointerException
    • IllegalArgumentException: 当向方法传递了一个不合法或不适当的参数时抛出。
      Thread t = new Thread(null, new Runnable() { ... }, "MyThread", -1); // 负的栈大小,抛出 IllegalArgumentException
    • IndexOutOfBoundsException: 当访问数组、列表或字符串的非法索引时抛出。
      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 或硬件层面的严重问题,程序无法控制 程序运行时的异常情况,程序可以预见和处理
可恢复性 通常不可恢复,程序会终止 通常可以恢复,通过捕获异常并采取相应措施
处理方式 不应该被捕获,应交
Java中Error与Exception有何核心区别?-图3
(图片来源网络,侵删)
分享:
扫描分享到社交APP
上一篇
下一篇