1.什么是异常?
程序在正常情况下是可以运行的,只是在遇到一些特殊情况的时候,导致程序中断/崩溃。
特殊情况:用户的非法输入,用户的磁盘空间已满,要读取的文件不存在,网络中断。
2.异常的类型
1)异常类型的根:java.lang.Throwable,Throwable作为类的根仍然为Object。
只有当对象是此类或者其子类之一的实例时,才能通过Java虚拟机或者Java throw语句抛出。
类似地,只有此类或其子类之一才可以是catch子句中的参数类型。
2)Throwable有两大子类:
Error:错误,用于指示合理的应用程序不应该试图捕获的严重问题。例如:VirtualMachineError(虚拟机错误),OutOfMemoryError,StackOverflowError
Exception:异常,指出了合理的应用程序想要捕获的条件。
3)Exception: 又可以分为两大类:
运行是异常:RuntimeException及其子类,非受检异常。
编译时异常:除了运行时异常,剩下的都是编译时异常。
如何区分是编译型异常还是运行时异常呢?
a.看类的继承关系图
b.看编译器的态度
编译器会提示你某个异常会发生,那么就是编译时异常,编译器压根不提示,就是运行时异常。
3.异常的处理
1)第一种方式,也是最根本的方式try...catch
注意点:catch的时候,异常的类型如果有父子关系的话,一定是子类在上,父类在下
执行的特点:如果try{}中没有发生异常,那么一个catch都不会去匹配。 如果try{}发生了异常,try中剩下的代码不执行了,在发生异常的位置会产生一个异常对象,并抛出
A:catch分支会从上往下,依次尝试去捕获这个异常对象。如果可以捕获到,那么就继续执行try...catch。
B:所有的catch都没有匹配,如果不是main方法,就会把异常往上抛,如果是main方法,程序挂掉。
4.finally块
1)finally块表示
a.无论try{}中代码是否发生异常,都要执行的代码
b.无论catch分支是否可以捕获异常,都要执行的代码
c.无论try和catch分支中是否有return语句,都要执行的代码
d.唯一finally不会执行情况是:在try{}后catch{}中有一句System.exit(0);退出JVM
2)finally和return
return语句在try和catch中
1)先把try中的return值放到“操作数栈”中
2)再去执行finally
3)把“操作数栈”结果返回并结束test方法的执行
return语句在try或catch中有,并且finally中也有
1)finally中的return语句会覆盖try或者catch中的return语句
5.throws转换异常处理位置
1.throws编译时异常
如果在编写方法体的代码时,某句代码可能发生某个编译时异常,不处理编译不通过,但是在当前方法体中不适合处理或无法给出合理的处理方式,就可以通过throws在方法签名中声明该方法可能会发生XX异常,需要调用者处理。
2.throws运行时异常
运行时异常类型,只是运行时异常类型,写或者不写对于编译器和程序执行来说都没用任何区别。如果写了,唯一的区别就是调用者调用该方法后,使用try...catch结构时,IDEA可以获取更多的信息,需要添加catch分支。
3.如果方法签名中有throws,对于方法重写有什么影响?
1)如果父类或者父接口被重写方法,没有抛出“编译时异常”,重写方法时,就不能throws编译时异常,但是可以throws运行时异常。
2) 如果父类或者父接口被重写方法,有throws“编译时异常”,重写方法时,可以不throws编译时异常。
A:重写方法时,可以不throws编译时异常。
B: 重写方法时,可以throws编译时异常,或者<=被重写方法的异常类型
C:对于运行时异常来说,没有限制。
总结:运行时异常,编译器不管。
编译时异常,<=
4.throws是加载方法()后面的
throw是在方法体中,一个语句,用于手动抛出一个异常对象。可以代替return语句,返回一个异常对象。
5.扩展练习
public int add(int x, int y) {
int result = x;
try {
result = x + y;
return result; //return 语句会:1)加载result的值,放到“操作数栈中” 2)执行finally 3)结束当前方法并返回
} finally {
result = x + y + 1; //没有对result做其他计算,也没有return,result新的值不会被加载到“操作数栈中”
}
}
@Test
public void test03() {
System.out.println(add(1, 2));
}
6.自定义异常类
1.自定义一个编译时异常类:自定义类并继承java.lang.Exception
2.自定义一个运行时异常类:自定义类 并继承java.lang.RuntimeException
注意:自定义的异常只能通过throw抛出
自定义异常:
1)要继承一个异常类型
2)建议至少两个构造器,一个是无参构造,一个是有参构造
3)自定义异常对象只能手动抛出。抛出后由try...catch处理,也可以甩锅throws给调用者处理。