大家好,我是指北君。
我们在上次模拟面试中聊到了 String最大长度是多少? 没看过的小伙伴,可以回过去看一下。 今天我们聊聊面试中经常会遇到的一个面试题, 对比 Exception 和 Error,说说运行时异常与一般异常有什么区别?
指北君:面试官,你好,我们可以开始面试了吗?
面试官:好的,那我们现在就开始吧。
面试官:上次我们聊到了 String 的最大长度问题,超过长度的话,JVM 会抛出异常。 我们平时写代码的时候,也经常会遇到很多大大小小的异常。
面试官:对比 Exception 和 Error,说说运行时异常与一般异常有什么区别?
指北君:Exception 和 Error 都继承自 Throwable ,在 Java 中 只有 Throwable 类型的实例才能被抛出或者捕获。
指北君:Exception 是程序正常运行中,可以预期的错误情况,希望能够被捕获,进行相应的处理。 而 Error 在正常情况下,不太可能出现的情况,绝大多数的 Error 都会导致程序崩溃,或者使得JVM 处于一个非正常的状态。而这些非正常的错误并不能被捕获进行相应的处理。
面试官:嗯,对 Exception 和 Error 的基础掌握的还不错。那异常种类有哪些?
指北君:Exception 可以分为检查异常和非检查异常,检查异常在我们的源代码中必须显示地进行捕获处理,且没有继承 RuntimeException,这类问题在编译期就可以确定的问题,比如 FileNotFoundException、IOException。
指北君:编译器对检查异常的处理要求:1.使用 try..catch 捕获。2. 不断向上抛出,交由 JVM 来处理。对于检查异常,需要尽快处理,如果任由异常不断上抛,每次上抛 JVM 都会获取抛出异常方法相应的堆栈信息,对性能会有一定的影响。
指北君:非检查异常继承了RuntimeException,也叫运行时异常,这类问题大部分属于代码逻辑问题,如 NullPointerException 、ArrayIndexOutOfBoundsException 之类的异常,只有在运行时才能知道是否有问题,异常在编译时不会检查。
指北君:编译器对非检查异常的处理要求:1.使用 try..catch 捕获。2. 不断向上抛出 3.不处理。在实际开发中,对于可能存在问题的点最好是用 try..catch 根据 Exception 的类型进行分类处理,减少因为可预见的异常导致的系统故障。
指北君:Error 也是非检查异常,OutOfMemoryError 这些也是编译期无法检查出来的。
面试官:既然你已经提到了异常最好还是使用 try…catch 来捕获处理,那我们在使用过程中,要注意哪些问题呢?
指北君:尽可能的不要捕获类似 Exception ,Error ,Throwable 之类的比较底层的通用型的异常。我们应该捕获特定型的异常。比如下面这个例子:
1 |
|
指北君:这段代码中我们使用了 Exception 做为捕获对象,而不是捕获 InterruptedException 。这就导致了隐藏了很多异常信息,我们不能够在后续的业务逻辑中更加准确的处理。 而且在我们平时工作中的协作也造成了一定的困难。
面试官:还有吗?
指北君:emm… 尽可能的不要生吞异常。 我们在开发中可能会遇到一些情况,觉得这个错误不重要,这个时候,有些开发人员就可能不对其进行抛出或者其他处理, 直接使用一个 e.printStackTrace() 就完事了。
面试官:使用 e.printStackTrace() 有什么问题吗?
指北君:我们来看这样一段代码:
1 |
|
在这里 e.printStackTrace() 直接把栈帧直接打印到标准输出中,这样一来,我们可能不太确定到底输出到哪里去了。
面试官:那这个是开发人员的问题,一般项目都会要求打到日志文件里的,还有其他的吗?
指北君:try…catch 代码段会产生额外的性能开销,我们在使用它捕获异常的时候,不建议使用一个 try…catch 包住整个方法这样的一大块代码,建议只在有必要捕获的代码块使用。另外 Java 在每实例化一个 Exception,都会对当时的栈进行快照,这是一个相对比较重的操作。如果发生的非常频繁,这个开销可就不能被忽略了。
面试官:嗯,今天就先到这里吧。
指北君:我的offer呢? 能稳吗?
面试官:嘿嘿嘿……
总结
今天通过模拟面试的形式,把Exception和Error 的区别做了一些解释,再通过对比检查异常和非检查异常,引出了平时使用 try…catch 需要注意的一些点。 希望对你们有帮助。