异常篇
异常类别
- java.lang.Throwable
- java.lang.Exception:checked Exception -> 强调要求调用者必须处理(评估调用者处理能力),从程序语法角度讲是必须进行处理的异常
- java.lang.RuntimeException:unchecked Exception -> 一般指程序逻辑错误,建议调用前自行验证以避免,由Java运行时系统自动抛出
- java.lang.Error:不希望被程序捕获或者是程序无法处理的错误,由JVM生成并抛出(通常终止线程),大多数错误与代码编写者所执行的操作无关
- java.lang.Exception:checked Exception -> 强调要求调用者必须处理(评估调用者处理能力),从程序语法角度讲是必须进行处理的异常
异常情形
- 定义:指阻止当前方法或作用域继续执行的问题,在当前环境下无法获得必要的信息来解决问题
- 抛出:在堆上创建一个异常对象,当前的执行路径被终止,从当前环境中弹出对异常对象的引用,异常处理机制接管程序
- 异常处理机制 -> 异常处理程序或者异常处理器,将程序从错误状态中恢复
- 抛出方式
- 抛出带状态码的异常
- 抛出指定类型的异常
- 捕获:异常抛出后,由运行时系统寻找合适的异常处理器,
- 运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行
- 当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适的异常处理器
- 当运行时系统遍历调用栈而未找到合适的异常处理器,则运行时系统终止
- 运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行
异常设计
设计原则
- 不要将异常处理用于正常的控制流,程序本身才是流程
- 对可以恢复的情况使用受检异常(建议通过一些状态检测手段来避免异常的发生),对编程错误使用运行时异常
- 优先使用标准的异常
- 每个方法抛出的异常都要有文档
- 保持异常的原子性
- 不要在catch中忽略掉捕获到的异常
设计思路
- 定义一个继承自RuntimeException的异常超类XmException
- 分别定义继承自XmException的异常,在配置文件中配置该异常对应的错误码
- 判断业务抛出的异常类型
- 已知自定义异常抛出
- 未知异常转化为XmException
- 统计未知异常,考虑是否新增自定义异常做定制化处理
- 数据返回前,获取异常中的ErrorCode与ErrorMsg拼入数据集合展示
使用心得
- 逻辑判断/校验以规避常见运行时异常
- 多重try/catch后面可添加catch(Exception)以捕获未知/遗漏异常
- 尽可能处理异常,恢复程序以保障业务逻辑的正常执行
- 涉及资源占用,尽量添加finally块以保障资源释放
面试问答
-
Java语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用?
答:Java通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。
在Java中,每个异常都是一个对象,它是Throwable类或其子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并可以对其进行处理。
Java的异常处理是通过5个关键词来实现的:try、catch、throw、throws和finally。
一般情况下是用try来执行一段程序,如果系统会抛出(throw)一个异常对象,可以通过它的类型来捕获(catch)它,或通过总是执行代码块(finally)来处理;try用来指定一块预防所有异常的程序;
catch子句紧跟在try块后面,用来指定你想要捕获的异常的类型;
throw语句用来明确地抛出一个异常;
throws用来声明一个方法可能抛出的各种异常;
finally为确保一段代码不管发生什么异常状况都要被执行,主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止;
try语句可以嵌套,每当遇到一个try语句,异常的结构就会被放入异常栈中,直到所有的try语句都完成。如果下一级的try语句没有对某种异常进行处理,异常栈就会执行出栈操作,直到遇到有处理这种异常的try语句或者最终将异常抛给JVM。 -
运行时异常与受检异常有何异同?
答:异常表示程序运行过程中可能出现的非正常状态。
运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误,只要程序设计得没有问题通常就不会发生。
受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发。
Java编译器要求方法必须声明抛出可能发生的受检异常,但是并不要求必须声明抛出未被捕获的运行时异常。