面向对象【异常处理】
在学习异常这一阶段过程中,为了方便记忆和理清思路,画了一个思维导图,一遍能够较快的形成知识框架。
1、异常(一)
1.1、什么是异常?
Java运行期间发生的问题
就是异常。
1.2、异常和错误的区别
异常:
程序发生异常时通常可以有针对性
的处理方式。
错误:
程序发生错误,一般不会有针对性
的处理方式。错误往往都是系统级别
的问题,都是JVM所在系统发生并反馈给JVM的,无法针对处理,只能修正代码
。
1.3、异常发生的原因
- 用户的
非法
操作; - 程序员编写代码时的
不恰当设计
; - 来自于
硬件设备故障
。比如:网络通信是连接中断,或者JVM内存溢出等。
1.4、异常的分类
编译时(检查)异常:
要么声明
,要么捕捉
。
运行时异常:
不需要捕捉或声明。
要声明也可以,如果声明了,无外乎就是让调用者给出处理方式。
1.5、异常的控制流程
方法栈遇到问题,异常处理的三种方式:
- 方法本身直接抓捕异常,不让这个“异常”对象沿着方法调用栈,继续向下传递;
- 方法本身直接抓捕异常,并继续让这个“异常”对象沿着方法调用栈,继续向下传递;
- 不去抓捕抓捕异常,就让这个“异常”对象沿着方法调用栈,继续向下传递,并且让方法从方法栈中直接弹出;
1.6、自定义异常
之前的几个异常都是java通过类进行的描述。并将问题封装成对象,异常
就是将问题封装成了对象。这些异常不好认,书写也很不方便,能不能定义一个符合我的程序要求的问题名称。既然JDK中是使用类在描述异常信息,那么我们也可以模拟Java的这种机制
,我们自己定义异常的信息,异常的名字,让异常更符合自己程序的阅读
。准确对自己所需要的问题进行类的描述
自定义异常注意事项:
- 所有的异常必须是Throwable的
子类
; - 如果想编写一个可以自动被异常处理或声明规则强制的检查异常,就需要
继承Exception
; - 如果想编写一个运行时异常,就需要
继承RuntimeException
;
1.7、异常的继承体系
1.8、捕获、声明异常
捕获:
Java中对异常有针对性
的语句进行捕获。
捕获格式:
try
{
//需要被检测的语句。
}
catch(异常类 变量)//参数。
{
//异常的处理语句。
}
finally
{
//一定会被执行的语句。
}
注意:
return不管是在try语句块中还是在catch语句块中,再执行这个return之前,都先执行finally语句块,必须进入到try语句块才会执行finally语句块。
声明(throws):
将问题标识
出来,报告给调用者
。
如果函数内通过throw抛出了编译时异常,而没有捕获,那么必须通过throws进行声明
,让调用者去处理。
如果一个方法没有捕获一个检查性异常,那么该方法就要使用throws关键字
来声明;
一个方法可以声明抛出多个异常
,多个异常之间用逗号
隔开。
throw和throws的区别:
- throw用在
函数内
。throws用在函数上
。 - thorw抛出的是异常
对象
。throws用于进行异常类
的声明,后面异常类可以有多个,用逗号隔开。
什么时候需要声明?
- **继承Exception,必须要throws声明。**一声明就告知调用者进行捕获,一旦问题处理了调用者的程序会
继续执行
。 - **继承RuntimeExcpetion,不需要throws声明的。**这时调用是不可能编写捕获代码的,因为调用根本就不知道有问题。一旦发生NoAgeException,
调用者程序会停掉
,并有jvm将信息显示到屏幕,让调用者看到问题,修正代码
。
2、异常(二)
2.1、经典案例介绍
老师
用电脑
讲课。
两个对象:
老师:
属性:姓名。
行为:讲课。
电脑:
行为:运行。
考虑问题:
- 电脑蓝屏–>异常。
- 电脑冒烟–>异常。
分析问题:
讲课中蓝屏,问题可以临时解决,是冒烟问题没有直接处理,所以就使用throws声明。但是发现,这个问题不应该属于讲课的问题。调用讲课方法的调用者是处理不了这个冒烟问题的。该调用者能处理的应该是冒烟导致的课程进行不下去的问题。应该在列出一个异常,课时停止异常。
class LanPingException extends Exception{ //电脑蓝屏异常描述
LanPingException() {
super();
}
LanPingException(String message) {
super(message);
}
}
class MaoYanException extends Exception{ //电脑冒烟异常描述
MaoYanException() {
super();
}
MaoYanException(String message) {
super(message);
}
}
class NoPlanException extends Exception{ //课时无法进行异常描述
NoPlanException()
{
super();
}
NoPlanException(String message)
{
super(message);
}
}
class NoteBook { //描述电脑对象
private int state = 2;
public void run()throws LanPingException,MaoYanException//方法上可以通过throws声明多个异常。
{
System.out.println("笔记本电脑运行");
if(state == 1)
throw new LanPingException("电脑蓝屏了");
if(state == 2)
throw new MaoYanException("电脑冒烟了");
}
public void reset()
{
state = 0;
System.out.println("电脑重启");
}
}
class Teacher{ // 描述老师
private String name;
private NoteBook book;
Teacher(String name)
{
this.name = name;
book = new NoteBook();
}
//讲课。
public void prelect()throws NoPlanException
{
/*
调用到了声明异常的方法,在这里到底是捕获好呢?还是声明好呢?
有具体的捕获处理方式吗?有,那就捕获,没有,那么声明。
我可以处理,重启就可以了,重启是电脑的功能。
*/
try
{
book.run();//对于声明多个异常的方法,在处理,需要定义多个catch与之对应。
}
catch (LanPingException e) {
//重启。
System.out.println(e.toString());//异常的名称+异常的信息。
// e.printStackTrace();
book.reset();
}
catch(MaoYanException e){
System.out.println(e.toString());
test();
//冒烟问题没有解决,继续声明throws出去。 throw e;
throw new NoPlanException(e.getMessage()+",课时停止");//异常转换。
}
System.out.println(name+"....讲课");
}
//留练习。
public void test()
{
System.out.println("做练习");
}
}
class ExceptionTest2 {
public static void main(String[] args) {
Teacher t = new Teacher("毕老师");
try {
t.prelect()
}
catch (NoPlanException e) {
System.out.println(e.toString());
System.out.println("换老师");
}
System.out.println("Hello World!");
}
}
2.2、finally关键字
概念:
有一些特定的代码无论异常是否发生,都需要执行。因为异常会引发程序跳转,导致有些语句执行不到
。无法满足这个需求。异常捕获处理时java提供解决方案,finally就是解决这个问题的,这个代码块中存放的代码都是一定会被执行。
应用场景:
定义一个功能往数据库中添加数据。
void add(Data data)throws NoAddException
{
//1、连接数据库。
try{
//2、添加数据。//添加数据时发生了异常情况。throw new SQLException();程序跳转,
就执行不到断开连接。
//而断开连接必须要执行,因为不执行,连接资源在浪费。
//无论是否发生问题,都需要执行断开连接的动作,从而释放资源。
}catch(SQLException e)
{
//解决数据库的问题。
//同时将问题告诉调用者。
throw new NoAddException();
}
finally
{
//3,断开连接。
}
}
总结:finally到底什么时候用?
只要程序中使用到了具体的资源(数据库连接,IO资源,网络连接socket等)需要释放,都必须定义在finally中
。你在定义程序,只要问题发生与否,指定程序都需要执行时,就定义finally中。包括return的内容也会直接执行。
2.3、异常细节
2.3.1、try catch finally 组合方式
try catch组合 : 对代码进行异常检测,并对检测的异常传递给catch处理,异常捕获处理。
void show()//不用throws
{
try{
throw new Exception();
}catch(Exception e)
{
//处理方式
}
}
try finally 组合:对代码进行异常检测,检测到异常后因为没有catch,所以一样会被默认jvm抛出。异常是没有捕获处理的。但是功能所开启资源需要进行关闭,所有finally。只为关闭资源。
void show()//需要throws
{
try{
throw new Exception();
}finally
{
//关闭资源
}
}
try catch finally 组合:检测异常,并传递给catch处理,并定义资源释放。
2.3.2、异常在方法复写中细节
异常在继承或者实现中的使用细节:
- 子类覆盖父类方法时,如果父类的方法声明异常,子类只能声明父类异常或者该异常的子类,或者不声明
越来越精细
。 - 当父类方法声明多个异常时,子类覆盖时只能声明多个异常的子集
越来越精细
。 - 当被覆盖的方法没有异常声明时,子类覆盖时无法声明异常的。
举例:父类存在这种情况,接口也有这种情况,
问题:接口中没有声明异常,而实现的子类覆盖方法时发生了异常,怎么办?
无法进行throws声明,只能catch的捕获。万一问题处理不了呢?catch中继续throw 抛出,但是只能将异常转换成RuntimeException子类抛出。