Java基础-异常
1、了解Java中的异常体系框架
介绍
异常就是程序运行过程中出现的错误。Java中,阻止当前方法或作用域的情况,称之为异常
Java语言的异常处理框架,是Java语言健壮性的一个重要体现
思想
Java把异常当做对象来处理,并定义一个基类Java.lang.Throwable作为所有异常的超类。在Java API中已经定义了许多异常类,这些异常类分为两大子类:
1)、错误:Error
包括虚拟机错误和线程死锁,一旦Error出现,线程就彻底的挂了,被称为程序终结者
这种情况仅凭程序是无法处理的,在程序中也不会对Error异常进行捕捉和抛出
2)、异常:Exception
主要指编码、环境、用户操作输入出现问题,Exception主要包括两大类:
-
- RuntimeException:运行时异常,也叫非检查异常(NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException、ArithmeticException),会由Java虚拟机自动抛出并自动捕获,此类异常的出现绝大数情况是代码本身有问题,应该从逻辑上去解决并改进代码
- 检查异常(其他的一些异常):引起该异常的原因多种多样,比如说文件不存在或者是连接错误。该异常必须手动在代码里添加捕获语句来处理该异常。从程序语法角度讲是必须警醒处理的异常,如果不处理,程序就不能编译通过。
2、Java异常的捕获和处理try、catch、finally关键字
思想:Java通过面向对象的思想进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java中每个异常都是一个对象,它是Throwable类或其子类的实例。当一个方法出现异常后边抛出一个异常对象,该对象中包含有异常信息,调用这个对象方法可以捕获到这个异常并可以对其进行处理
关键字:Java的异常处理是通过5个关键字来实现的:try、catch、finally、throw、throws。
-
- try
try语句不可以独立存在,必须与catch或者finally块同存,负责捕获异常,一旦try中发现异常,程序的控制权将被移交给catch块中异常处理程序
-
- catch
负责如何处理。比如发出警告:提示、检查配置、网络连接、记录错误等,执行完catch块之后程序跳出catch块,继续执行后面的代码。
编写catch块的注意事项:多个catch块处理的异常类,要按照先catch子类后catch父类的处理方式,因为会就近处理异常
-
- finally
最终执行的代码,用于关闭和释放资源
try{ //一些会抛出的异常代码 }catch(){ //处理该异常的代码块 }catch(){ //处理该异常的代码块 }finally{ //最终要执行的代码 }
3、Java异常的捕获和处理之三种异常处理模型
Java的异常梳理模型给予三种操作:
-
- 声明异常
throws-----声明将要抛出何种类型的异常。当某个方法可能抛出某种异常时用于throws声明可能抛出的异常,然后交给上层调用它的方法程序处理
-
- 抛出异常
throw------将产生的异常抛出,是抛出异常的一个动作。一般会用于程序出现某种逻辑时程序会主动抛出某种特定的类型的异常
-
- 捕获异常
当抛出一个异常时,可以在try-catch块中捕获它并进行处理
1、若执行try块的过程中没有异常发生,则跳过catch子句。
2、若是出现异常,try块中剩余的语句不在执行
3、开始逐步检查catch块,判断catch块的异常类实例是否是捕获的异常类型
4、匹配后执行相应的catch块中的代码
5、如果异常没有在当前的方法中被捕获,就会被传递给该方法的调用者,这个过程一直重复,知道异常被捕获或传给main方法(交给jvm来捕获)
4、Java异常体系中throw和throws的比较
-
- throws出现在方法函数头;而throw出现在函数体。
- throws表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一定抛出了某种异常对象。
- 两者都是消极处理异常的方式,只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。
5、Java异常体系中catch捕获异常的顺序
-
- 一个通用父类可以派生出各种异常类,如果一个catch块可以捕获一个父类的异常对象,它就能捕获哪个父类的所有子类的异常对象
- 如果捕获的是多个同类型异常,则子类异常在前,父类异常灾后,不然会导致编译错误
这是因为父类异常囊括了子类异常,如果福尔利异常在前,子类异常永远捕获不到,导致优势或无法准确描述错误信息
6、Java异常体系中try-catch-finally的执行流程
执行流程
-
- try块中引起异常,异常代码之后的语句不再执行
- 若被catch块捕获,执行匹配的catch块,然后执行finally语句
- 若catch块不能捕获异常,则执行finally语句,之后将异常传递给这个方法的调用者
- finally在try中的return语句执行后,return返回主调函数指点执行
return返回值各种情况
-
- try,catch,finally语句块中均有return,三个语句块中都没有抛出异常:将执行finally语句块中的return。
- try,catch,语句块中均有return,finally语句块中无return,try中抛出异常切catch捕捉到异常:将执行catch语句块的return
- try,catch,语句块中均有return,finally语句块中无return,三个语句块中窦娥米有抛出异常:将执行try语句的return
- try,catch,finally语句块中均有return,try语句块中抛出异常切catch捕捉到异常:将执行finally语句块的return
- try,catch,语句块中均有return,finally语句块中无return,try语句块中抛出异常且catch捕捉到异常,catch语句块有抛出异常:将抛出catch语句块中的抛出的异常
- try,catch,finally语句块中均有return,try语句块中抛出异常且catch捕捉到异常,catch语句块有抛出异常:将执行finally语句块中的return
- try,catch,语句块中均有return,finally语句块中无return,try语句块中抛出异常与catch要捕获的异常类型不一致:将抛出try语句块的异常
- try,catch,finally语句块中均有return,try语句块中抛出异常与catch要捕获的异常类型不一致:将执行finally语句块中的return
- try,catch,finally语句块中均有return,try和catch语句块没有抛出异常,finally语句块中抛出异常:将抛出finally语句块中异常
7、Java异常体系中try-finally的使用把场景
流程
-
- try块中引起异常,异常代码之后的语句不再执行,直接执行finally语句
- try块没有引发异常,则执行完try块就执行finally语句
使用场景
-
- try-finally可用于不需要捕获异常的代码,可以保证资源在使用后被关闭
如:IO六中执行完相应操作后,关闭相应资源;使用Lock对象保证线程同步,通过finally可以保证锁会被释放;数据库连接代码时,关闭连接操作等等
8、Java异常体系中finally什么时候不会被执行
-
- 在前面的代码中用了system.exit(0)退出程序
- finally语句中发生了异常
- 程序所在的线程死亡
- 关闭CPU
- 在 Java 虚拟机退出时, Daemon 线程中finally不一定会执行
9、Java异常体系值自定义异常
为什么要使用自定义异常,有什么好处?
-
- 我们在工作的时候,项目是分模块或者分功能开发的,基本不会你一个人开发一整个项目,使用自定义异常类就统一了对外异常展示的方式
- 有时候我们遇到某些校验或者问题时,需要直接结束掉当前的请求,这时就可以通过抛出自定义异常来结束
- 自定义异常可以在我们项目中某些特殊的业务逻辑时抛出异常。比如"中性".equals(sex),性别等于中性时我们哟啊抛出异常,而Java是不会由这种异常的。
- 使用自定义异常继承相关的异常来抛出处理后的异常信息可以隐藏底层的异常,这样更安全,异常信息也更加的直观。
缺点
-
- 毋庸置疑,我们不可能期待JVM自动抛出一个自定义异常,也不能期待JVM 会自动处理一个自定义异常
- 发现异常、抛出异常以及处理异常的工作必须考变成人员在代码中利用异常处理机制自己完成。这样就相应的增加了开发成本和工作量,所以项目没有必要的话,也不一定非哟啊用上自定义异常,要能够自己去权衡
使用
-
- 所有异常都必须是Throwable的子类
- 如果希望写一个检查性异常类
- 如果你想写一个运行时异常类,那么需要继承RuntimeExection类