异常之总结

本文围绕Java异常展开,介绍了异常的定义、分类(运行时异常和编译时异常),阐述了Throwable、Exception和Error的关系及区别。还讲解了异常传播机制、解决方案,如提前判断、修改代码、try - catch等,分析了try - catch - finally的含义及使用要点,最后列举了常见异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是异常:程序执行过程中的不正常情况。

异常在表现形式上分两种:

1、运行时异常 语法没有错误,编译通过了,但是运行起来后程序在控制台报错,并停止运行。 2、编译时异常 你们还以没有遇到过,他是语法没有错误,但是编译不通过。用鼠标指过去以后,会提示:有未处理的异常,后面跟异常的名字。

Trowable是Excepyion和Error的父类。

Exception,ErrorException -- Error是所有错误类的父类,异常Error -- 错误他们都是我们程序在语法正确的情况下,在运行期或编译期出现的问题。但是两者的严重层度和解决方案不一样。Exception是所有异常的父类 , Exception更多的是指可以用代码去解决的问题;Error往往不是代码级别的问题,往往是运行环境或硬件问题。 Exception和Error都是Throwable的子类,所以他们都可以抛出,当然也都可以catch。

Exception的子类RuntimeException --- 它和它的子类是运行时异常;--- 也就是在编译期不检查是否处理,没处理的话运行时报错。 非RuntimeException --- 它们和它们的子类是编译时异常;--- 要求编译期必须解决,否则编译不通过。

异常发生在哪个线程当中 --- 这个目前不需要,因为单线程;

发生了什么异常 --- 看异常的名字,对常见异常要逐渐形成经验性的解决方案。

发生在哪里? --- 从上往下找第一行你写的代码 为什么会有多个异常发生位置?这是因为异常的传播机制。在程序运行阶段,一旦发生了异常,那么JVM会自动产生一个对应类型的异常对象,把本次发生异常的基本信息封装进去。然后在当前代码处,查看是否有该异常的处理方案;如果没有,那么JVM会提前结束这个方法,然后带着异常对象返回方法调用处。接着,在方法调用处查看是否有该异常的处理方案,如果没有,那么再结束这个方法,返回它的调用处。如此执行下去,直到main方法如果也没有解决,那么终止main方法,打印异常信息在控制台。而main方法的终止,程序肯定也终止了。

这个异常的传播机制又告诉了我们额外的两个知识点:

1、方法结束的方式不仅仅是遇到方法的结束"}" 或 “return”关键字;遇到未处理的异常,方法也会结束。而所有的结束,都是返回方法调用处!

2、如果要求发生异常,程序不结束,那么我们其实是可以在异常的传播路径的任意位置进行处理的。当然,不同的位置,效果有差异。

异常的解决方案 :

1、通过提前判断,把异常扼杀在摇篮中

2、逻辑错误,修改代码

3、try-catch 往往是学得内容不够,无法在运行期去判断或解决问题。

try-catch-finally含义:

try的含义就是试,所以在try块中就是书写有可能发生异常的代码块,我们试着让它去执行;

try不能够单独存在的,后面必须跟上catch 或 finally;同样catch和finally也是不能单独存在的,必须配上try;

catch的含义就是捕获,catch的圆括号中是表明我们要捕获哪种异常;花括号是用来确定捕获住以后,要做什么。 在catch的圆括号当中,就是一个异常变量的声明;然后一旦发生异常,执行进入catch块,就会拿这个变量去匹配(instanceof)JVM产生的异常对象。匹配上说明这个catch块就是处理这个异常的,没有匹配上,说明这个catch块不是处理它的。 注意:只要匹配上,那么这个异常就算是被抓住了,就不会继续往上传播,程序回到正确逻辑执行。

如果在try的代码中,可能出现多种异常,那么后面是可以接多个catch块的,每个catch捕获一种。 一个try块内部可以有多种异常,但每次只会发生一种,然后停止执行try剩余代码,然后从上往下依次匹配每个catch块,谁匹配住了进入谁内部,然后执行完catch,跳到最后面去。 如果同时有多个catch块,那么这多个catch捕获的exception如果有继承关系,那么必须是先捕获子类,再捕获父类。如果捕获的多个exception没有继承关系,那么谁先谁后就没有关系了。

finally块是用来书写不管是否发生异常,都必须要执行的代码。往往是:资源的回收,清理动作。

finally、final、finalize的区别:

final 是一个关键字 修饰变量不变,那就是常量;修饰方法不变,那就是不能被重写;修饰类不变,就是不能被继承。 finally 是一个关键字,用来在try-catch后面表示不管是否发生异常都必须要执行的代码块。 finalize 不是关键字,他是方法名;它是Object的一个方法。这个方法是专门用来销毁对象的,由GC调用。

finally不管是否发生异常都会被执行,那么能不能不让它执行?比如:在它之前加return?结论:加return也能被执行,代码级别只有System.exit(0)可以阻止finally的执行。那么,它在return之前还是在return之后被执行呢?其实return语句虽然在代码中只是一条语句,但是在底层执行的时候不是一个动作。finally是在return语句已经做好返回准备了以后,被执行,然后再发生真正返回动作。--- 换句话,在finally当中是不能够修改在他之前的return后面的返回值的。

try-catch-finally的掌握,除了语法的掌握,更重要的一点是处理完异常以后,要让程序能够回到正确逻辑下继续运行。

编译时异常引出:

在现在大家的开发中,异常往往是由JVM在运行时给我们产生的。实际开发中,我们能不能够自己产生一个异常呢? 通过测试我们可以看到,虽然我们能够在代码中自己产生一个异常对象,但是这个异常对象只是安安静静地呆在内存当中,并没有异常传播或者终止程序等效果。 如果想要这些效果,那么我们需要在异常对象的前面加一个throw关键字,这个时候这个异常对象才能够在运行时被纳入到异常的传播机制当中。 但光加throw是不够的,因为这个时候在编译期间,已经通过硬代码明确看到这里会出异常。所以,编译器就要求先提出解决方案,然后再执行。 

对于编译时异常来说更多的是用于底层代码设计人员使用的一种手段,所以大家现在并没有看到它的实际使用。它的存在主要是一个异常到底该谁处理的职责问题。因为底层代码中有一些初始条件来自于外部的调用者(传参),这个数据的正确性不是由底层方法的实现者来控制的。因此如果由这个数据的正确性出现了问题,那么就不应该由底层这个使用者来进行处理,必须通知调用者去检查,从而才设计了抛出这么一个机制的存在。 抛出机制并没有处理异常,仅仅是在编译期强制调用者通过语法去检查明确自己的传入的数据对不对。

常见异常:

1.ArrayIndexOutOfBoundsException数组越界异常:

2.ArithmeticException算术异常

3.ClassCastException类型转换异常

4.NullPointerException空指针异常

5.FileNotFoundException找不到文件异常

6.RuntimeException运行时异常
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值