异常概述:运行时发生的不正常情况
在java中用类的形式对不正常的情况进行了描述和封装对象。
描述不正常的类,称之为异常类。
异常就是java通过面向对象的思想将问题封装成了对象,用异常类对其进行描述。
不同的问题用不同的类进行具体的描述,比如角标越界,空指针等。
异常体系两大类:
无论是error,还是Exception,问题发生就应该可以抛出,让调用者知道并处理,该体系的特点就在于Throwable及其所有子类都具备可抛性。
Throwable:
① 一般不可处理的。Error 特点:是由JVM抛出的严重性问题;这种问题一般不针对处理,直接修改程序。 ② 可处理的。Exception 可抛性:被throws 和 throw 关键字所操作的类和对象都具备可抛性 该体系的特点:子类的后缀名都是用其父类名作为后缀名,阅读性很强。
异常分类:
检测性异常:即除RuntimeException及其子类以外的异常。这类异常在编译时就进行检测,不处理不能通过; 非检测性异常:即运运行时异常RuntimeException及其子类。这类异常不处理变异也可以通过,如果有抛出 直接抛到控制台让调用者进行修正;
自定义异常:
要么继承 Exception 要么继承 RuntimeException
如果抛出一个在Java中没有定义过的异常,这时就需要自定义创建一个异常类。
注:自定义一个异常类,必须要继承一个异常体系才可以被抛出,被throw throws所操作
异常抛出注意事项:
子类覆盖父类只能抛出父类的异常或者子类或者子集
① 子类在覆盖父类方法时,父类方法如果抛出了异常,那么子类的方法只能抛出父类异常或者该父类异常的子类; ② 如果父类抛出多个异常,那么子类只能抛出父类异常的子集
注意:如果父类的方法没有抛出,那么子类覆盖式也决不能抛出,只能try
异常处理:throw,throws和try...catch;finally;
用类封装描述异常(称为异常类),不同的问题不同的类,当程序中遇到可能会发生异常的时候抛出异常类或进行捕获异常处理。
异常抛出
throw 和 throws 的区别:
① throw:使用在函数内,throw抛出的是异常对象;throw new 异常类 ( )
② throws:使用在函数上,throws抛出的是异常类,可抛出多个,用逗号隔开( , );throws 类名,...,...,
PS:当 throw new RuntimeException的时候,不用throws
throw:
抛出一个异常,一般是在函数代码块的内部,当程序出现某种逻辑错误时由程序员主动抛出某种特定类型的异常
public void getOffer(String s) {
if(s.equals("abc")) {
throw new NumberFormatException();
}
if(s.equals("")) {
throw new Exception("输入参 S 不能为空");
} else {
System.out.println(s);
}
}
throws:
可能抛出异常的声明 (用在声明方法时,表示该方法可能要抛出异常)
当某个方法可能会抛出某种异常时用于throws 声明可能抛出的异常,然后交给上层调用它的方法程序处理
public class testThrows(){
public static void function() throws NumberFormatException{
String s = "abc";
System.out.println(Double.parseDouble(s));
}
public static void main(String[] args) {
try {
function();
} catch (NumberFormatException e) {
System.err.println("非数据类型不能强制类型转换。");
}
}
异常捕捉
捕获异常:try...catch 关键字捕获异常 tay...catch放在异常可能会发生的地方
try
{
//需要被检测异常的代码(保护代码块)
}catch(异常类 引用名)//该类用于接收发生的异常对象
{
//处理异常的代码(异常类)
}catch(异常类 引用名)
{ //可多重捕获,可在try语句后面添加任意数量的catch块.
/* 如果保护代码中发生异常,异常抛给第一个catch块,异常相匹配的话,则在这里被捕获。如果不匹配,
就会传给第二个catch块,如此直到异常被捕获或通过所有catch块为止 */
//一个try块下的多个catch异常类型有父子关系,应该将子类异常放在前面,父类异常放在后面,这样保证每个catch块都有存在的意义
}
finally //通常用于关闭(释放)资源
{
//finally代码块里面的动作必定会执行,无论有没有发现捕获异常,都一定会执行的代码
//一个try至少要有一个catch块,否则, 至少要有1个finally块。但是finally不是用来处理异常的,finally不会捕获异常。
//finally主要做一些清理工作,如流的关闭,数据库连接的关闭等。
}
try catch finally 代码块组合特点:
① try catch finally ② try catch(多个)当没必要资源需要释放时,可以不用定义finally ③ try finally 异常无法直接catch处理,但是资源需要关闭
捕获处理原则:
在写程序时,对可能会出现异常的部分通常要用try{...}catch{...}去捕捉它并对它进行处理;
用try{...}catch{...}捕捉了异常之后一定要对在catch{...}中对其进行处理,那怕是最简单的一句输出语句,或栈输入e.printStackTrace();
try对应多个catch时,如果有父类的catch语句块,一定要放在下面。
如果是捕捉IO输入输出流中的异常,一定要在try{...}catch{...}后加finally{...}把输入输出流关闭;
如果在函数体内用throw抛出了某种异常,最好要在函数名中加throws抛异常声明,然后交给调用它的上层函数进行处理
异常处理原则:
① 函数内部如果抛出需要检测的异常,那么函数上必须要声明。否则必须要在函数内使用try...catch捕捉,否则编译失败;
( RuntimeException以外的异常需要throws声明 )
② 如果调用到了声明异常的函数,要么ctry catch要么throws,否则编译失败。 ③ 功能内容可以解决是用catch;解决不了用throws告诉调用者,由调用者解决。 ④ 一个功能如果抛出了多个异常,调用时必须有多个catch进行针对性处理。内部有几个需要检测的异常,就抛几个异常,抛出几个就catch几个;