这节内容不多也不难,很快就可以拿下。
一、异常的三种常见形式:
【1】:算术异常 【2】:数组越界异常 【3】:空指针异常
二、异常的体系结构:
【1】:Thorwable:是异常体系的顶层类,其派生出两个重要的子类,Error和 Exception。
【2】:Error(错误):指的是Java虚拟机无法解决的严重问题,比如:JVM的内部错误、资源耗尽等,典型代表:StackOverflowError和OutOfMemoryError,一旦发生回力乏术。
【3】:Exception(异常):异常产生后程序员可以通过代码进行处理,使程序继续进行。比如感冒、发生。我们平时所说的异常就是Exception。
三、异常的分类:
(1):编译时异常,也称为受检查异常。
(2):运行时异常,也称为非受检查异常。包括算数异常、数组越界异常、空指针异常。
四、异常的处理:
(1):事前防御型: 在操作前之前就做充分的检查。
(2):事后认错型:先操作,遇到问题再处理。
五、异常的抛出:(throw关键字)
定义:在java中可以借助throw关键字,抛出一个指定的异常对象,将错误信息告知给调用者。
注意:抛出一个运行时异常是不需要处理的,但是如果是一个编译时异常,我们需要通过thorws关键字去处理。
语法:thorw new XXXException(“异常产生的原因”);
(1):抛出一个自定义异常:
【1】:throw必须写在方法体内部。
【2】:抛出的对象必须是Exception或者Exception的子类对象
【3】:如果抛出的是RunTimeException或者RunTimeException的子类对象,则可以不用处理,直接交给JVM处理。
【4】:如果抛出的是编译时异常,用户必须处理,否则无法通过编译。
【5】:异常一旦抛出,其后的代码不会执行。
(2):输出结果:
(2):编译时异常:
第34行代码报错,因为CloneNotSupportedException属于编译时异常,不属于运行时异常,不能通过throw关键字在类内部解决,要通过throws关键字来解决。
六、异常的捕获:(throws关键字)
当方法中抛出异常时,用户不想处理该异常,此时可以借助throws将异常抛给方法的调用者处理。即当前方法不处理异常,提醒方法的调用者处理异常。
语法:修饰符 返回值类型 方法名(参数列表)throws 异常类型1,异常类型2....{
【1】:throws必须跟在方法的参数之后。
【2】:声明的异常必须是Exception或者Exception的子类。
【3】:方法内部如果抛出了多个异常,throws必须跟多个异常,用逗号隔开。
(1):此时48行代码报错,是因为test方法没有处理该异常。可以通过throws关键字来抛出异常,从而消除跑错(见后续代码)。
(2): 此时42行代码在main方法中调用test方法会报错,是因为在test方法中通过throws关键字告诉程序员这里有异常,想让调用它的main方法去处理,此时main方法也没有处理,所以42行代码报错。此时JVM调用main方法,交给JVM去处理了。
(3): 在main方法中使用throws关键字抛出对异常进行处理,此时42行调用test方法的代码不再报错。
七、try-catch捕获并处理:
throws并没有对代码进行真正的处理,而是将异常报告抛给异常方法的调用者,由调用者处理,如果想要真正对异常进行处理,就要用到try-catch。
(1):这里是10/a会出现算术异常,但是程序员并没有去处理,这时候程序就会交给JVM去处理,此时程序就会异常终止。此时程序员可以通过try-catch来处理异常。
(2):输出结果:此时程序异常终止,退出代码为1,正常情况下退出代码为0。
(3):语法:将可能有问题的代码放到try中,catch中放可能出现的异常类型,最好不要放Exception,此时异常太模糊了,编译器难以辨别到底是哪种异常。且catch一定要捕获一个对应的异常类型,否则还是会交给JVM来处理,还是会报错。此时程序员自己把异常处理了。
(4):输出结果:此时代码无异常正常输出。
(5):try块内代码发生异常,后续代码不会被执行。
(6):输出结果: 第110行代码被打印,第111行代码未被执行。
(7):try中可能会抛出多个不同的异常对象,则必须用多个catch来捕获。
(8):输出结果: 出现算术异常后,try中后续的空指针异常将不会被执行。
程序只会同时抛出一个异常,不会同时抛出多个异常。
(9):e.printStackTrace():可以帮我们打印栈上的异常信息,快速定位到异常信息。
(10):输出结果:输出算术异常。
(11):如果异常之间有父子关系,一定是子类异常在前catch,父类异常在后catch,否则语法错误。
(12):输出结果:
八、finally:
定义:有些特定的代码,无论程序是否发生异常,都要被执行。在程序正常或异常退出时,必须要对资源进行回收。因为异常会引发程序的跳转,可能导致有些语句执行不到,finally就是来解决这个问题的。
(1): finally,不管是否抛出异常,都被执行了。
(2):输出结果:
(3):fianlly,不管是否抛出异常,都被执行了。
(4):输出结果:
(5)finally的主要作用是:资源关闭:
(6):输出结果:finally始终会被执行。
九、throw和thorws的区别是什么?
答: throws声明方法可能会抛出的异常,throw用来抛出异常。
十、fianlly中的语句一定会被执行吗?
答:一定会被执行。
十一、异常的处理流程:
十二、自定义异常:
(1):登录功能(用户名错误版):
分别定义了两个变量userName和passWord,分别赋值。之后定义了一个方法loginInfo,通过throws声明了UserNameException和PassWordException两个可能出现的异常,之后通过if语句来判断输入的用户名是否与默认的用户名相同,如果不相同,就通过throw关键字抛出UserNameException异常,下面的密码语句同理。
(2):通过new关键字实例化了一个login对象,然后在try-catch调用loginInfo方法并赋值,此时用户名错误,密码正确。然后catch分别抛出UserNameException和PasswordException异常。
第23行和第26行代码:定位代码目前出现的问题。
(3):定义了一个UserNameException类,继承了RuntimeException类,然后分别给出了一个无参构造方法和有参构造方法。
【1】:自定义异常类,然后继承自Exception或RuntimeException。
【2】:实现一个带有String类型参数的构造方法,参数含义:出现异常的原因。
(4): 定义了一个PassWordException类,继承了RuntimeException类,然后分别给出了一个无参构造方法和有参构造方法。
(5):输出结果:第10行和第21行代码有误。
(6)登录功能:用户名正确版,可以正常运行:
将第21行代码中用户名的赋值改为admin,此时用户名正确。
(7):输出结果: