初识异常
异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰。
Throwable类是Java异常类型的顶级父类, 其又派生出Error类和Exception类; JDK中创建了一些常用的异常类, 当然也可以通过自定义的方式创建异常.
Error类以及他的子类的实例,代表了JVM本身的错误。错误不能通过代码处理.
Exception以及他的子类,代表程序运行时发送的各种不期望发生的事件,可以被Java异常处理机制使用,是异常处理的核心。
一. java异常的分类
- 非检查异常/运行时异常: 编译阶段不会报错, 运行时才出现问题, 如Error, NullPointerException, ArrayIndexOutOfBoundsException等
- 检查异常/编译时异常: 编译阶段就要求处理, 要么抛出, 要么捕获, 如SQLException, IOException, ClassNotFoundException等
二. 初识异常
异常是在执行某个函数时引发的,而函数又是层级调用,形成调用栈的,因为,只要一个函数发生了异常,那么他的所有的caller都会被异常影响。当这些被影响的函数以异常信息输出时,就形成的了异常追踪栈。
如果没有使用任何异常处理机制, 异常最终会抛给JRE, 导致程序终止
三. 异常处理的基本语法
在编写代码时, 针对编译时异常有两种处理方式(机制), 使用try…catch…finally语句块处理它。或者,在函数签名中使用throws 声明交给函数调用者caller去解决。
try起来:
try:
1. try块中放可能发生异常的代码。
2. 如果执行完try且不发生异常,则接着去执行finally块和finally后面的代码(如果有的话)。
3. 如果发生异常,则尝试去匹配catch块。
catch:
1. 每一个catch块用于捕获并处理一个特定的异常,或者这异常类型的子类。Java7以后可以将多个异常声明在一个catch中。
2. catch后面的括号定义了异常类型和异常参数。如果异常与之匹配且是最先匹配到的,则虚拟机将使用这个catch块来处理异常。
3. 在catch块中可以使用这个块的异常参数来获取异常的相关信息。异常参数是这个catch块中的局部变量,其它块不能访问。
4. 如果当前try块中发生的异常在后续的所有catch中都没捕获到,则先去执行finally,(注)然后到这个函数的外部caller中去匹配异常处理器。
5. 如果try中没有发生异常,则所有的catch块将被忽略。
finally:
1. 无论异常是否发生,异常是否匹配被处理,finally都会执行。
2. finally主要做一些清理工作,如流的关闭,数据库连接的关闭等。
注意: 异常匹配是按照catch块的顺序从上往下寻找的,只有第一个匹配的catch会得到执行。匹配时,不仅运行精确匹配,也支持父类匹配,因此,如果同一个try块下的多个catch异常类型有父子关系,应该将子类异常放在前面,父类异常放在后面,这样保证每个catch块都有存在的意义。
当一个函数的某条语句发生异常时,这条语句的后面的语句不会再执行,它失去了焦点。执行流跳转到最近的匹配的异常处理catch代码块去执行,异常被处理完后,执行流会接着在“处理了这个异常的catch代码块”后面接着执行。
良好的习惯: 再try里打开资源, 连接, 再finally里关闭
抛出去:
通过throws关键字实现, 它仅仅是将函数中可能出现的异常向调用者声明, 而自己不具体进行处理, 一方面是方法本身不知道如何处理这种异常, 另一方面是可能让调用者处理更好, 或者说调用者需要为可能发生的异常负责.
四. throw关键字
&emsp可以通过这个关键字手动显示的抛出一个异常, 其后面必须跟一个异常对象, throw语句必须写在函数中, 执行这个语句的地方就是异常抛出点, 这和JRE自动形成的异常抛出点没有任何差别
五. 自定义异常
实现方式:
继承Exception或RuntimeException类实现规则: 必须包含如下构造函数
一个无参构造 一个带有String参数的构造, 并传递给父类构造 一个带有Throwable参数的构造, 并传递给父类构造 一个带有String参数Throwable参数的构造, 并都传递给父类构造 具体可参考源码的异常定义规则, 如IOException
六. 异常的注意事项
当子类重写父类的带有throws声明的函数时, 其throws声明的异常必须在父类异常的可控范围内, 目的是为了实现多态;比如父类throws了IOException, 子类就必须throws这个异常或这个异常的子类
java中的异常是线程独立的, 这样不会影响到其他线程的执行, 也不至于出了异常一旦没有任何代码处理就导致程序终止
七. 不得其解finally
在try语句块中即便有return, break, continue等改变执行流的语句, finally也是会执行的
finally中的return会覆盖try或者catch中的返回值
finally中的return会抑制try或者catch中的异常
finally中的异常会覆盖try或者catch中的异常