#异常捕获与处理

异常与错误的区别

在我们的生活中,总会有出现许许多都各种各样问题,而在这许许多多中问题中就包含有异常和错误。在Java中就有两种错误,语法错误和语义错误,异常就是在程序中的一种导致程序中断运行的指令流,是一个程序在编译运行时出现的错误,也是VM虚拟机通知我们出现了一个可以补救的错误,它有别于错误,错误时VM的一个故障,两者的区别在于,前者是在程序运行中出现的错误,是能够让电脑进行捕获并且做出补救措施即异常处理,而后者是JVM发出的错误操作以及无法通过代码对其进行补救的实实在在的错误

异常体系结构

首先是Java中最大的父类——Object,然后其子类Throwable之下包含有两个子类——Exception类和Error类,其中Exception类即为异常类,Error类则表示是的“错误”的类,如下图所示在这里插入图片描述
其中,Exception类之中有个特别一点的类,叫RunTimeException类,这个类特别之处在于运行的时候出现的异常,是所有可以在运行时抛出异常的父类;图中的受查异常是指编译器在编译时进行校验的异常

注意:
1.捕获的异常不能方法在比其更小的异常类中,但可以放入比其大的异常类中,比如:捕获一个空指针异常时可以放入NullPointerException 类中,也可放入Exception类中,但,捕获异常为Exception异常时不能放入NullPointerException 类中,就类似于集合中的包含于的问题
2.在达到某种目的的情况下,可以将所有捕获的异常都用Exception来捕获,比如:为了方便不用进行详细到什么类型的的异常捕获,可以将所有的异常用Exception进行捕获

异常处理

再发生异常的时候,我们通过捕获异常,来进行进一步的异常处理
而对异常的处理有以下几种常见的方法:
1.try{}…catch(){}…finally{}方法进行处理异常
2.throws关键字将异常抛出
3.throw关键字抛出异常
4.自定义异常

try{}…catch{}语句的异常处理

1.格式:
(1) 对不同的异常进行不同的处理
try{
//有可能发生异常的代码段
}catch(异常类型1 对象名1){
//对捕获的异常进行的处理1
}catch(异常对象2 对象名2){
//对捕获的异常进行的处理2
}…
finally{
//异常的同统一出口
}

(2)对不同的一场进行相同的处理
try{
//有可能发生异常的代码段
}catch(异常类型1 | 异常类型2 |…对象名1){
//对捕获的异常进行的处理
}

2.处理流程:
(1) 产生异常的时候,系统会自动对该异常产生一个异常实例化对象,同时由后方的catch语句进行处理
(2)在try语句中发生的异常会自动进行与catch的匹配,若异常不在try中发生,可会将异常抛出给调用者
(3)若匹配成功,则交由catch进行处理
3.finally语句:
作为异常的统一出口,不管是否产生异常都会执行此段代码,但是在程序遇到突然断电或者程序突然终止虚拟机时,fianlly语句才不会执行
在对于基本类型和引用类型的fianlly语句中,返回的值不同如下两个图
引用类型
在这里插入图片描述
在即将要返回p时,备份下来的是地址,所以在返回p时,从person的地址0x123中返回p的值为28
基本类型
在这里插入图片描述
在即将要返回p时,备份下来的是返回值,所以在返回p时,从备份值中返回p的值为10

throws关键字

将出现的异常抛出去,由调用者来进行处理该异常
格式:
返回值 方法名称() throws 异常类型{
}

传参导致出现的异常或传递的指令不对,则通过throws将其抛出去

thorw关键字

将出现的人为的异常抛出去,通过throw抛出的一个异常类实例对象
格式:
throw new 异常类型(参数列表)
或者
throw 异常类型的对象
方法出现了不符合代码内容的异常,则可以通过throw将其实例化抛出

throw与throws两者使用的不同可以举个栗子:比如,在申请注册QQ的时候,我们需要填写个人信息,当我们填写到年龄的时候,就会有个规定,必须时整数类型的值,当我们有人填写18.5的值的时候就会出现问题,我们既可以理解为是输入的类型不对,而后就通过throws将其抛出,在另一种情况,我们输入的是整数类型的值,但是在我们输入10000的时候,即会认为该用户为10000岁而不符合我们所认为的常理时,则通过throw将其实例化来抛出

throw与throws的区别

共同点:
1.两者均为消极的处理异常方式,因为两者均为抛出异常,而并未对异常进行处理
不同点:
1.throw时语句抛出的异常,而throws是方法抛出的异常声明
2.throws出现在方法函数头,throw出现在函数体内
3.throw抛出的异常由方法发体内的语句执行,而throws抛出的异常由方法的调用者执行

自定义异常

顾名思义,可以自己定义一个异常类,当出现相符的异常时,交由自己定义的自定义异常类对其进行异常处理
格式:
class 自定义异常类名 extends 异常类型{
// 继承一个异常类,表示一个自定义异常类
//对出现的异常进行的处理
};

异常处理常见面试题

1.try-catch-finally 中哪个部分可以省略?
catch和finally两者中可以省略一个,但不能都省略,总不能就try发现了异常就啥事儿也不干吧
注意:当我们省略了catch之后,便不会再捕获异常了
2.try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
finally语句会执行
执行流程
1.先计算返回值,并将其备份
2.执行到finally是便将返回值返回
注意
1.返回值在finally执行之前就已经备份好了,所以不管finally做任何改变都不会改变返回值,但如果返回时备份的是地址,则仍然可以对该地址内的数据进行更改
2.若程序中包含有return语句则程序会在执行中提前结束
3.当try或者catch中停止了JVM(虚拟机),比如停电,或者通过终止JVM(虚拟机)的代码:System.exit(0),则finally语句都不会执行

总结

对异常的捕获和处理有了较为深刻的理解,一开始在学习中有遇到很多比较区分的东西,就比如throw和throws两者均为抛出异常,但不知道两种抛出异常方法的区别,觉得用那个应该都可以,学习完了就会理解,throw抛出的异常时不符合我们所认为的常理的而异常,而throws时抛出系统在编译运行时出现的异常,在我的博客中可能还有很多的不足和缺陷,可以来吐槽吐槽我