发布时间:2022-12-04 文章分类:编程知识 投稿人:李佳 字号: 默认 | | 超大 打印

读本篇文章之前,如果让你叙述一下 Exception Error Throwable 的区别,你能回答出来么?
你的反应是不是像下面一样呢?

一、Exception Error Throwable 关系

直接看下图,展示了三者之间的关系:

【Java面试指北】Exception Error Throwable 你分得清么?

二、对比一个 Error 和 Exception

你在面试中也许会被问到:

NoClassDefFoundError 和 ClassNotFoundException 有什么区别?

首先,我们看这俩名字,一个是 Error 另一个是 Exception,从上面的介绍以及看下面的继承图可以得到:ClassNotFoundException 应是编码时要被捕获的异常,NoClassDefFoundError 是编译通过了,但运行时产生的重大问题。
【Java面试指北】Exception Error Throwable 你分得清么?

进一步的:
ClassNotFoundException 是运行中动态加载类时出现的问题。
举例来说,使用 Class.forName 来动态加载一个类,如果你不显示的 catch 处理,ide 都会给你提示,并且也过不了编译。

// 错误写法
public void except() {
    Class.forName("com.test.aaa");
}
// 正确写法
public void except() {
    try {
        Class.forName("com.test.aaa");
    } catch (ClassNotFoundException e) {
        // throw or log
        throw new RuntimeException(e);
        // log.error("ClassNotFoundException: ", e);
    }
}

【Java面试指北】Exception Error Throwable 你分得清么?

NoClassDefFoundError 是编译时没问题,但运行时 new 实例找不到。
比如在一个类中引用另一个类的函数,编译后把另一个类的 class 文件删掉:

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello world!");
        MyPrint.printName();
    }
}
public class MyPrint {
    public static void  printName() {
        System.out.println("my name is zhangsan");
    }
}

使用 javac 编译,再删除 MyPrint.class

$ tree com
com
└── shuofxz
    ├── Main.class
    ├── Main.java
    ├── MyPrint.class  # 把这个文件删掉
    └── MyPrint.java

执行程序,就会看到 NoClassDefFoundError,并且是由 ClassNotFoundException 引起的。

Exception in thread "main" java.lang.NoClassDefFoundError: com/shuofxz/MyPrint
	at com.shuofxz.Main.main(Main.java:6)
Caused by: java.lang.ClassNotFoundException: com.shuofxz.MyPrint
	at java.net.URLClassLoader.findClass(URLClassLoader.java:387)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:419)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:352)
	... 1 more

三、捕获异常代码常见问题

一)看下面的代码有什么问题?

try {
  // 业务代码
  // ...
  Thread.sleep(1000L);
} catch (Exception e) {
}

二)再看下面这个,增加了异常打印逻辑,还有什么问题不?

try {
    // 业务代码
    // …
} catch (IOException e) {
    e.printStackTrace();
}

三)再来看下面的:

try {
    // 业务逻辑 A
    // 业务逻辑 B
    // 业务逻辑 C
    // ...
} catch (Exception e) {
    log.error("have exception", e);
}

四)我们前面介绍了Exception、Error、Throwable,为什么代码中经常能看到 catch XXException,却几乎看不到 catch XXErrorcatch Throwable 呢?

三、小结

本篇介绍了 Exception Error Throwable 的区别,并给出了相关例子帮助理解。
回到开头的问题:「叙述一下 Exception Error Throwable 的区别」你心里有数了么?