Java核心36讲之Exception和Error有什么区别?

极客时间,杨晓峰老师的课,特别好的课程,学习一下,记一些东西,微信搜索“极客时间”就ok啦

前面一篇:Java核心36讲之对Java平台的理解

关于Exception,复习一下学习的时候写的关于异常的笔记:Java异常Exception,突然感觉之前记得很清楚哈哈,现在看也觉着很不错

问题:对比Exception和Error,另外运行时异常与一般异常有什么区别?
回答:分析Exception和Error的区别,理解Java处理机制,阐释清楚就ok

例如:(原谅我直接粘贴的原来的博客)
首先看图(最好记住这张图吧,面试的时候也可以直接画出来)
在这里插入图片描述

Java中异常都是Throwable子类的实例
  1. Error(错误)
    程序无法处理的错误
    出现此错误表示运行程序中较严重问题,表示代码运行时JVM出现的问题。这些错误是不可查的,在应用程序的控制和处理能力之外,大多数是程序运行时不允许出现的状况。

  2. Exception(异常)
    程序本身可处理的异常
    Exception 类有一个重要的子类 RuntimeException,RuntimeException 类及其子类表示“JVM 常用操作”引发的错误。例如,若试图使用空值对象引用、除数为零或数组越界,则分别引发运行时异常(NullPointerException、ArithmeticException)和 ArrayIndexOutOfBoundException

还有一种分类方法是按可检查、不可检查分类
  1. 可查的异常(Checked Exceptions)
    编译时要求必须处理的异常可查异常一定程度是可预计的,一旦发生这种异常状况,必须采取某种方式处理 。
    除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常,这种异常的特点是Java编译器会检查它,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则不会通过编译
  2. 不可查异常(Unchecked Exceptions)
    包括RuntimeException及其子类和错误(Error)

下面才是重点!!!!!

需要注意

  1. 理解Throwable、Exception、Error的设计和分类,掌握应用最为广泛的子类,以及如何自定义异常
    不得不说我之前写的那篇博客里面还真有,链接就在上面,当然这里也是哈哈(ps:我真不是在误导你点我的博客,而是希望大家理解更清楚一点,找东西更快速一点)
  2. 理解Java语言中操作Throwable的元素和时间,掌握基本语法和懂得如何处理典型场景。
    Java语言的发展也引入了更加便利的特性,比如try-with-resources和multiple catch。在编译时期,自动生成对应的处理逻辑,比如自动按约定俗成close那些扩展了AutoCloseable或者Closeable的对象。
    示例代码:
try (BufferedReader br = new BufferedReader(…);
     BufferedWriter writer = new BufferedWriter(…)) {// Try-with-resources
// do something
catch ( IOException | XEception e) {// Multiple catch
   // Handle it
} 

  1. 注意尽量不要捕获类似Exception这样的通用异常,而是应该捕获特定异常,相信这点大家都很清楚,不隐藏我们的目的,这里就不贴代码了。
  2. 不要生吞(swallow异常)。说实话刚开始有点不理解,但是老师给举得例子是非常易懂的,看下面
//第一段代码
public void readPreferences(String fileName){
	 //...perform operations... 
	InputStream in = new FileInputStream(fileName);
	 //...read the preferences file...
}

//第二段代码
public void readPreferences(String filename) {
	Objects. requireNonNull(filename);
	//...perform other operations... 
	InputStream in = new FileInputStream(filename);
	 //...read the preferences file...
}

如果filename是null,那么程序就会抛出NullPointerException,如果第一时间暴露出问题,那么就不需要太复杂的定位,反而变得非常直观。(突然想到Kotlin的可空类型确实弥补了Java的这个小缺点)
是不是突然有点明白了,这就是Throw early, catch late 原则。
前面代码介绍说明的是Throw early,至于catch late,捕获异常后应该怎么处理?最差的就是“生吞异常”,但是实在掩盖问题。生吞异常,往往是基于假设这段代码可能不会发生,或者感觉忽略异常是无所谓的,但是如果不把异常抛出,或者也没有输出到日志(Logger)之类,程序可能在后续代码就以不可控的方式结束,无法判断到底是哪里抛出了异常,以及是什么原因产生了异常。
如果实在不知道如何处理,可以选择保留原有异常的cause信息,直接再抛出或者构建新的异常抛出去,因为在更高层面,有了清晰的业务逻辑,往往会更清楚合适的处理方式。

有的时候,会根据需要自定义异常,这个时候除了保证足够的信息,还有两点需要考虑:

  1. 是否需要定义成Checked Exception,作为异常设计者,往往有充足信息进行分类,初衷更是为了从异常情况进行恢复。
  2. 在保证诊断信息足够的同时,也要考虑避免包含敏感信息,因为那样可能导致潜在的安全问题。比如用户数据一般是不可以输出到日志里面的。

从性能方面角度审视一下Java的异常处理机制
  1. try-catch代码单会产生额外的性能开销,即往往会影响JVM对代码进行优化,所以建议仅捕获有必要的代码段,尽量不要一个大的try块包住整段的代码;与此同时,利用异常控制代码流程,远比我们通常意义上的条件语句(if/else、switch)低效。
  2. Java每实例化一个Exception,都会对当时的栈进行快照,这是一个相对比较的操作,如果发生频繁,则开销就不可以忽略。

好像还有个经典的面试题目叫
NoClassDefFoundError 和 ClassNootFoundException有什么区别?
回答:
NoClassDefFoundError是一个错误(Error),而ClassNOtFoundException是一个异常,在Java中对于错误和异常的处理是不同的,我们可以从异常中恢复程序但却不应该尝试从错误中恢复程序。

ClassNotFoundException的产生原因:

  1. Java支持使用Class.forName方法来动态地加载类,任意一个类的类名如果被作为参数传递给这个方法都将导致该类被加载到JVM内存中,如果这个类在类路径中没有被找到,那么此时就会在运行时抛出ClassNotFoundException异常。

  2. 解决该问题需要确保所需的类连同它依赖的包存在于类路径中,常见问题在于类名书写错误。

  3. 另外还有一个导致ClassNotFoundException的原因就是:当一个类已经某个类加载器加载到内存中了,此时另一个类加载器又尝试着动态地从同一个包中加载这个类。通过控制动态类加载过程,可以避免上述情况发生。

NoClassDefFoundError产生的原因在于:

  1. 如果JVM或者ClassLoader实例尝试加载(可以通过正常的方法调用,也可能是使用new来创建新的对象)类的时候却找不到类的定义。要查找的类在编译的时候是存在的,运行的时候却找不到了。这个时候就会导致NoClassDefFoundError.
  2. 造成该问题的原因可能是打包过程漏掉了部分类,或者jar包出现损坏或者篡改。解决这个问题的办法是查找那些在开发期间存在于类路径下但在运行期间却不在类路径下的类。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值