JavaSE:异常

1、什么是异常

在生活当中,不管是人还是动物又或是植物,都会生病;在程序中也是,作为程序猿,虽然我们会尽力将程序写的完美,可难免会出现一些问题~

在程序执行过程中,发生的一些不正常行为,就叫做异常。

2、异常的体系结构

我们可以观察到,Throwable是异常体系的顶层类,其派生出两个子类Exception(异常)和Error(错误)。

Exception:就是我们平时说的异常,可以理解为我们现实生活中的生病,我们可以通过代码来处理异常,使程序正常运行。

Error指的是Java虚拟机无法解决的严重问题,比如:JVM的内部错误、资源耗尽等,例如:StackOverflowError(栈溢出错误),一旦发生就回力乏术。

3、异常的分类

Exception继承于Throwable,也就是说,异常其实是一个类,而异常又分为运行时异常(非受查异常)和编译时异常(受查异常)。

3.1 运行时异常(非受查异常)

其实大家对非受查异常并不陌生,我们平时遇到的例如:数组越界异常、空指针异常、算数异常、类型转换异常等都是非受查异常。

算数异常:

数组越界异常:

空指针异常:

3.2 编译时异常(受查异常)

在程序编译期间发生的异常,称为编译时异常,也称为受检查异常。

例如当我们拷贝自定义类型的对象时,我们没有在main方法中声明异常,就会划红线报错:

受查异常必须进行处理,否则程序无法运行。

抛出异常后,异常警告消失,程序可以执行了。

但是需要注意的是,我们这里只是声明了异常,并没有处理掉这个异常,如果出现了异常,只会交给JVM来处理。一旦交给JVM处理,程序就会立即终止。

那,我们该如何去处理异常呢?

4、异常的处理

在Java中,异常处理主要用到5个关键字:throws、try、catch、throw、finally

4.1 throws 声明异常

我们在上述举例受查异常时就已经提到了throws关键字,当方法中可能会抛出编译时异常时,我们可以使用throws来声明这个异常,告诉调用者:"你要帮我处理掉这个异常!"(该方法不处理,声明异常让调用者处理)

也就是说当前方法不处理这个异常,而提醒方法的调用者,让调用者帮它处理。

当前方法不处理异常而使用throws声明异常后,那该方法的调用者只有两条路走:

1. 老老实实的帮它处理掉这个异常(使用try{}catch{} ,下面会讲)

2. 不想帮它处理异常,也使用throws来声明这个异常(就是我们前面举例受查异常时所用到的解决方法)

也就是说,当编译时异常出现后,必须进行处理!(方法内部处理,或者方法调用者来处理,总之必须处理!)否则程序无法运行!

对于throws关键字有以下几点值得注意:

1. throws必须跟在方法的参数列表之后

2. 声明的异常必须是 Exception 或者 Exception 的子类

3. 方法内部如果抛出了多个异常,throws之后必须跟多个异常类型,之间用逗号隔开,如果抛出多个异常类型 具有父子关系,直接声明父类即可

4. 调用声明抛出异常的方法时,调用者必须对该异常进行处理,或者继续使用throws抛出

4.2 try-catch 捕获处理异常

异常抛出后throws并没有处理异常,只是进行了声明,要想捕获处理异常,需要用到try-catch

语法格式:

我们在try{ }代码块中放入可能出现异常的代码,使用catch来进行捕捉,

代码举例:

我们来运行上图的代码:

需要注意的是:

1. 当程序抛出异常后,如果catch中有该异常的捕捉,则程序会直接跳到这个catch块执行catch中的代码,并从这个catch块继续往下执行(程序不会异常终止)。如果catch中没有捕捉到该异常,则会交给JVM来处理,程序会立即终止。(也就是说我们可以用catch来捕捉多个异常,以免异常被交给JVM处理使程序异常终止)

2. try块中只会抛出一个异常,当异常被抛出,会立即来到对应的catch中进行捕捉,try块内抛出异常位置之后的代码将不会被执行,也就是说即使try块后面的代码有异常,也不会再抛出,所以不会抛出多个异常。

对于printStackTrace方法的作用,就是打印出该异常出现的位置,便于程序猿的发现,

如下图讲解:

try-catch知识点总结:

1. try块内抛出异常位置之后的代码将不会被执行

2. 如果抛出异常类型与catch时异常类型不匹配,即异常不会被成功捕获,也就不会被处理,继续往外抛,直到 JVM收到后中断程序----异常是按照类型来捕获的

3. try中可能会抛出多个不同的异常对象,则必须用多个catch来捕获----即多种异常,多次捕获

4.如果异常之间具有父子关系,一定是子类异常在前catch,父类异常在后catch,否则语法错误

5.由于 Exception 类是所有异常类的父类,因此可以用这个类型表示捕捉所有异常(可以放到最后用来兜底,但是极不推荐只使用Exception来捕获异常 )

4.3 throw 手动抛出异常

我们之前讲到的异常的抛出,都是由于触发了JVM的机制由JVM来抛出的异常,这里的throw关键字是用来手动抛出异常的

例如:

因为异常都是一个类,所以我们throw出相应异常的对象就可以,也可以在构造方法传入相关信息。

其实,throw主要用于抛出自定义类型的异常。

需要注意:

1. throw必须写在方法体内部

2. 抛出的对象必须是Exception 或者 Exception 的子类对象(不能抛出自定义类的对象)

3. 如果抛出的是 RunTimeException 或者 RunTimeException 的子类(运行时异常),则可以不用处理,直接交给JVM来处理(但程序会立即终止)

4. 如果抛出的是编译时异常,用户必须处理,否则无法通过编译

5. 异常一旦抛出,其后的代码就不会执行

4.4 finally 

不管有没有抛出异常,是否被捕获,finally中的代码一定会执行的,一般在finally中进行一些资源清理的收尾工作。

比如,当程序抛出异常时,要么异常被catch捕获,执行catch后代码;要么异常没有被catch捕获,程序异常终止。这两种情况都是会使程序的某些部分没有被执行,而程序中会有必要的部分必须被执行,例如:资源的关闭,那就可以把这段必须被执行的代码放入finally中。

其实,我们平时用的输入方法就是一种资源,我们利用finally来关闭它:

运行1:

运行2:

运行3:

我们发现,不管有没有抛出异常,也不管抛出异常后catch有没有捕获,哪怕是交给JVM来处理异常(程序异常终止),finally中的代码都被执行了。

我们还可以提前将方法返回:

我们发现,即使方法已经遇见return返回,后面finally中的代码仍然被执行了。

5、自定义异常类

Java当中虽说有着丰富的异常类,但是我们在开发过程中难免会遇见一些不能表示的异常,这时,我们就可以自定义异常。

如何自定义异常呢?

我们可以参考Java给出的异常源码(仅当参考):

仿照源码,创建自定义类,使之继承于Exception 或者 RuntimeException类,给出无参和带参的构造方法。

我们可以模拟实现用户登录界面,当用户名或者密码输入错误时,可以抛出自定义的用户名异常或者密码异常:

首先,写出自定义的用户名异常和密码异常:

当输入用户名或者密码错误时会抛出对应异常:

运行展示:

1.密码输入错误

2.用户名输入错误

3.输入正确

创建自定义异常类需要注意以下几点:

1. 自定义异常通常会继承自 Exception 或者 RuntimeException

2. 继承自 Exception 的异常默认是受查异常(必须捕获处理掉异常)

3. 继承自 RuntimeException 的异常默认是非受查异常

OK~本次博客到这里就结束了,

感谢大家的阅读~欢迎大家在评论区交流问题~

如果博客出现错误可以提在评论区~

创作不易,请大家多多支持~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值