异常的概念
在Java当中,将程序执行过程中发生的不正常行为称为异常。
1.算数异常
抛出的异常其实就是一个类
2.空指针异常
注:抛出异常后后面的内容将不能打印
3.数组越界
从上述类型都可以发现,异常有专门的类来进行描述
4.编译时异常
异常的分类
根据不同时期不同表现可以把异常分为:编译时异常(受查异常) 运行时异常(非受查异常)
注:语法错误不是异常
运行时异常都是继承于RuntimeException这个类
1.Throwable是异常的顶层类,派生出两个子类 Error 和 Exception
2.Error一般是指java虚拟机无法解决的错误
3.Exception一般发生后程序员可以通过代码使其恢复正常,就像感冒发烧吃药
异常的处理
1.LBYL:(在操作前做充分检查)事前防御型
每操作一步前先检查上一步是否正常
2.EAFP:(事后获取原谅比事前获取容易)事后认错型
先操作遇到问题再处理
优势:正常流程和错误流程是分离开的,程序员更关注正常流程,代码更清晰,容易理解代码,异常处理的核心思想就是EAFP
异常处理的五个关键字:throw ,try,catch, final,throws
异常的抛出
17行的是我们手动抛出的异常,22行是跟他同类型的异常,只要我们解决了上面的异常,底下的异常也会被解决
这种我们一般用在自己自定义的异常
注意事项:
1.throw必须在方法内部
2.抛出的对象必须是Exception或者Exception的子类对象
3.如果抛出的是RuntimeExcept或者RuntimeException的子类,则可以不用处理,直接交给jvm即可
4.如果抛出的是编译异常/受查异常,那么用户必须自行处理,否则无法通过编译
5.异常一旦抛出,其他代码将不会执行
如果抛出的是受查异常,那么需要去处理这个异常
异常的捕获
主要有两种:异常声明:throws 和 try-catch捕获处理
异常声明
一般放在方法参数之后,当方法中抛出编译异常,用户不想处理时,此时就可借助throws将异常抛给方法的调用者。即当前方法不处理异常,提醒方法的调用者处理异常
当我们没有解决这个异常的时候,就会把这个异常交给jvm去处理,一旦交给jvm,程序就崩溃了
注意:
1.throws必须出现在方法参数之后
2.声明的异常必须是Exception或者Exception的子类
3.方法内部如果抛出了多个异常,throws之后必须跟多个异常类型,之间用,隔开,如果抛出多个类型的异常具有父子关系,直接声明父类即可
4.调用方法声明异常时,调用者必须对该异常进行处理,或者继续用throws抛出
异常的处理
try catch
1.try抛出异常,从上往下执行,先遇到谁执行谁,跟catch程序无关
2.catch里面直接写异常类Exception这种一劳永逸的做法是不可取的
3.如果先catch Exception类再 catch它的子类,catch 子类会报错,如果想执行子类,则可以将子类放在前面,父类放在后面兜底
4.catch当中程序的书写,不影响异常的捕获
5.catch当中没有捕获的异常,那么就会交给jvm处理,程序就立即中止了
问题:会不会同时抛出两个及两个以上异常?
答:不会,在同一时间只会抛出一个异常。
finally
**有些特定的程序,不论程序是否发生异常,都需要执行,比如程序中打开的资源:**网络连接,数据库等,在程序退出时,必须对资源进行回收。另外,因为异常会引发程序的跳转,可能导致有些语句执行不到。finally就是用来解决这个问题的
1.不管是否在try当中抛出异常,finally里面的代码终将被执行。(一般用于资源的释放)
2.如果在try()写资源那么就不用在finally当中将资源释放,不用写close
3.注意:不建议在finally中写return
关于调用栈:先进后出,后进先出
异常处理流程
1.程序执行try当中的代码
2.如果代码出现了异常,就会结束try当中的代码,寻找看有没有catch捕获的异常
3.如果有,则执行catch中的代码
4.如果没有则会将异常传递给上层调用者
5.无论是否匹配到异常类型,finally中的代码都会被执行
6.如果上层调用者也没有处理这个异常,则会一直传递,如果main方法也没有处理,就会交给jvm来处理,程序就会终止。
自定义异常类
注意事项:自定义异常类会继承Exception类(编译时异常/受查异常)或者RuntimeException(运行时异常/非受查异常)
在自定义的异常类里,可以写不带参数和带参数的构造方法,方便我们使用。