Java基础-异常
@[作者:JasonPeng, 版本 :1.0.0]
一、没有异常处理机制的困惑
没有异常处理机制存在的缺点:
①:使用方法的返回值来表示异常的情况有限,无法穷举到所有的异常情况。
②:异常流程代码和正常流程代码混合在一起,大大增加了程序的复杂性,可读性降低。
③:随着系统规模的不断扩大,程序的可维护性极低。
解决方案:
①:把不同类型的异常情况描述成类(称之为异常类)。
②:分离异常流程代码和正确的流程代码。
③:灵活处理异常,如果当前方法处理不了,应该交给调用者处理。
二、异常体系
非正常情况出现后程序会中断:
①:Error:表示错误,一般只JVM相关的不可修复的错误。如,系统崩溃,内存溢出,JVM错误等,有JVM抛出,我们不需要处理。几乎所有的子类都是以Error作为类名的后缀。
②:Exception:表示异常,指程序中出现的不正常的情况。该问题可以被修复(处理异常),几乎所有的子类都是以Exception作为类名的后缀。
三、捕获异常
(一)使用try-catch捕获单个异常
语法如下:
try{
编写可能出现异常的代码
}catch(异常的类型 e){
处理异常的代码
// 记录日志、打印异常信息、继续抛出异常
}
注意:try和catch不能单独使用,必须连用。
(二)获取异常信息
Throwable类的方法:
①:String getMessage():获取异常的描述信息。原因(提示给用户的时候,就提示错误的原因)。
②:String toString():获取异常的类型和异常描述信息(不用)。
③:void printStackTrace():打印异常的跟踪栈信息并输出到控制台。包含了异常的类型,异常的原因,还包括了异常出现的位置,在开发和调试阶段,都要使用printStackTrace。
重要:在catch语句块中,必须写e.printStackTrace(),目的:查看异常的具体信息,方便调试和修改。
(三)使用try-catch捕获多个异常
try{
编写可能会出现的异常代码
}catch(异常类型A e){ // 当try中出现A类型异常,就该catch来捕获
处理异常的代码
// 记录日志、打印异常信息、继续抛出异常
}catch(异常类型B e){ // 当try中出现B类型异常,就该catch来捕获
处理异常的代码
// 记录日志、打印异常信息、继续抛出异常
}
注意:
①:一个catch语句,只能捕获一种类型的异常,如果需要捕获多个异常,就得使用多个catch语句。
②:代码在一瞬间只能出现一种类型的异常,只需要一个catch捕获,不能同时出现多个异常。
四、finally代码块
finally语句块表示最终都会执行的代码,无论有没有异常。
什么时候代码必须最终执行:
当我们使用try语句块中打开了一些物理资源(磁盘文件、网络连接、数据库连接等),在使用完毕后,最终都要关闭打开的资源。
finally的两种语法:
①:try…finally:此时没有catch来捕获异常,因为此时根据应用场景,我们会抛出异常,自己不处理。
②:try…catch…finally:自身需要处理异常,最终还要关闭资源。
使用finally和不使用finally的区别,必须使用finally才能保证最终必须执行的代码。
如果finally有return语句,永远返回finally中的结果,要避免该情况。
五、异常分类
异常(Exception)的分类:
①:编译时期的异常:checked异常:在编译时期,就会检查,如果没有处理异常,则编译失败。
②:运行时期的异常:runtime异常:在运行时期,检查异常,在编译时期运行异常编译器不会检测(不报错)。
运行异常:在编译时期可处理,可不处理。
六、抛出异常
(一)throw语句
运用于方法内部,抛出一个具体的异常对象:
throw new 异常类("异常信息");终止方法。
一般当一个方法出现不正常情况的时候,我们不知道应该返回什么,此时就返回一个错误,在catch语句块中继续向上抛出异常。
return是返回一个值,throw是返回一个错误,返回给该方法的调用者。
(三)throws语句
运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常)。
private static int divide(int num1, int num2)throws Exception{}
如果每一个方法都放弃处理异常,都直接通过throws声明抛出,最后异常会跑到main方法,如果此时main方法不处理,继续抛出给JVM,底层的处理机制就是打印出异常的跟踪栈信息。
runtime异常,默认就是这种处理方式。
方法的覆盖(override):
一同:方法的签名必须相同。
两小:
①:子类方法返回类型和父类方法的返回类型相同或是其子类。
②:子类方法不能声明抛出新的异常。
一大:子类方法的访问权限必须大于等于父类方法的访问权限。
(四)自定义异常类
在开发中自己根据业务的异常情况来定义的异常类。
自定义异常类的定义:
①:自定义一个受检查的异常类:自定义类并继承于:java.lang.Exception。
②:自定义一个运行时期的异常类:自定义类并继承于:java.lang.RuntimeException。
(五)异常转义和异常链
①:异常转义:当位于最上层的子系统不需要关心底层的异常细节时,常常的做法是捕获原始的异常,把他转换为一个新的不同类型的异常,再抛出新的异常。
②:异常链:把原始的异常包装为新的异常类,从而形成多个异常的有序排列,有助于查找程序异常的根本原因。
七、Java7的异常新特性
①:增强throw
②:多异常捕获
③:自动资源关闭,必须实现AutoCloseable才能使用。
八、最佳实践
处理异常的原则:
①:异常只能用于非正常情况。
②:需要为异常提供说明文档,比如Java doc。
③:尽可能避免异常(如NullPointerException)。
④:异常的粒度很重要,应该为一个基本的操作定义一个try-catch块,不要为了简便,将几百行代码放到一个try-catch块中。
⑤:不建议在循环中进行异常的处理,应该在循环外对异常进行捕获处理。
⑥:自定义异常尽量是用RuntimeException类型的。
反馈与建议
- 博客:我的CSDN博客
- 邮箱:pengtdy@gmail.com
- QQ交流群:644402856(新)
感谢你阅读这篇博客。如果您喜欢这篇博客就请关注我和朋友一起分享吧!