在一个方法的运行过程中,如果发生了异常,则这个方法生成代表该异常的一个对象,并把它交给运行时系统,运行时系统通过相应的代码来处理这一异常。
生成异常对象交给运行时系统,我们称为抛出异常throw。
运行时系统在方法的调用栈中查找,从生成异常的方法开始进行回溯,知道找到包含相应异常处理的方法为止。这叫做捕获一个异常catch。
异常处理机制
- 程序执行过程中,如果出现异常,会自动生成一个异常类对象,该异常类对象被提交给运行时系统,这个过程叫抛出异常。抛出异常也可以由程序强制执行。
- 运行时系统接收到异常对象,会寻找能处理这一异常的代码并把当前异常交给其处理,这一过程叫做捕获。
- 如果运行时系统找不到可以捕获异常的方法,则运行时系统终止,相应程序退出。
Trowable
Java的异常类都是java.lang.Trowable
的子类。它有两个字类,一个是Error
一个是Exception
Error:JVM系统内部错误,资源耗尽等严重问题,由系统保留
Exception:编程错误或偶然的外在因素,供应用程序使用。
Exception的子类是IOException和RuntimeException
异常
异常分两种,一种是必须处理的,一种是不要求处理的。
对于必须处理的,要么捕获catch,要么抛出(声明throws) 即要么捕,要么抛
抛出异常
在本函数中不处理该异常,而是把它抛出(在定义时,使用throws),让调用该函数的方法try catch 去处理
必须在方法头中增加throws异常类名列表
- 系统自动抛出异常。当程序语句出现一些逻辑错误、主义错误或者类型转换错误时,系统会自动抛出异常
- 语句抛出异常,借助于throw语句 人为抛出异常(显示异常)有两种方法
隐式异常:非法操作 例如程序中的式子是1/x,传入的x是0,此时为非法操作
1.直接抛出异常类实例
throw new ExceptionType(...);
2.先定义异常类对象并实例化,然后抛出
ExceptionType e = new ExceptionType(...);
throw e;
以下程序是抛出显示异常并处理的情况
int age = 12;
try{
if(age<0||age>120)
throw new ExceptionType("超出范围"); //直接抛出实例
}catch(Exception e){ //捕捉异常对象 实例化 e是异常对象的引用
e.printStackTrace(); //该函数在命令行打印异常信息在程序出错的位置及原因
}
在一个方法中抛出的异常,该方法可以对其进行处理(try catch),也可以不处理。
不处理的情况是把异常向上传递,交给调用该方法的方法进行处理。如果该异常时隐式异常,则不需要throws声明抛弃。如果该异常是显示异常,则需要throws做声明抛弃,将其交给上层调用。
throws声明:
修饰符 返回值类型 方法名(参数列表) throws 异常类名列表
{
}
如果方法中的throw语句不止一个,方法头的异常名列表也不止一个,要包含所有可能的异常。
不处理的隐式异常,不必用throws声明抛给上级,自动传递给调用该方法的方法
public static int A(int x){
int z = 0;
z = 110/x;
return z;
}
public static void main(String[] args){
int a = 0;
try{ //自动传给调用该函数的函数,并在结果处报异常
A(0);
}catch(Exception e){
e.printStackTrace();
}
}
throw抛出显示异常 不处理,必须用throws声明抛给上级调用
public static int A(int x) throws Exception{ //抛给上级
int z = 0;
if(x==0)
throw new Exception("除数为0"); //显示抛出异常
z = 110/x;
return z;
}
public static void main(String[] args){
int a = 0;
try{
A(0); //在调用时处理异常
}catch(Exception e){
e.printStackTrace();
}
}
throw : 将产生的异常抛出(强调的是动作),抛出的既可以是异常的引用,也可以是异常对象。(位置: 方法体内)
throws : 如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常。用它修饰的方法向调用者表明该方法可能会抛出异常(可以是一种类型,也可以是多种类型,用逗号隔开)(位置: 写在方法名 或方法名列表之后 ,在方法体之前。)
注意 : 调用可能会抛出异常的方法,必须添加try-catch代码块尝试去捕获异常 或者 添加throws 声明 来将异常 抛出给更上一层的调用者进行处理,这里需要注意一个细节:新的异常包含原始异常的所有信息
throw与throws
1、throws出现在方法函数头,而throw出现在函数体。
2、throws表示出现异常的一种可能性,并不一定会发生这些异常,throw则是抛出了异常,执行throw则一定抛出了某种异常对象。
3、两者都是消极处理异常的方式(这里的消极并不是说这种方式不好),只是抛出或者可能抛出异常,但不会由函数去处理异常,真正的处理异常由函数的上层调用处理。
————————————————
看我
看我
- 在覆盖的方法中声明异常
父类中的方法如果声明了throws异常,则子类覆盖父类的方法也可以throws异常。
子类方法抛出的异常只能是父类方法抛出异常的同类或子类。见上图
import java.io.*;
class A{
public void method() throws IOException{}
}
class B extends A{
public void method() throws FileNotFoundException{}
}
class C extends A{
public void method() throws Exception{} //Error!!!
}
捕获异常
当一个异常被抛出后,有专门的语句来接收这个被抛出的异常对象。被捕获或接收后,系统终止当前流流程而跳转至专门的异常处理模块,或直接跳出当前程序和虚拟机回到操作系统。
异常对象依靠以catch语句为标志的异常处理语句块来捕捉和处理。
catch语句块至少有一个catch语句或finally语句
格式为:
每个catch都应该与一个try对应。
try { 语句组 }catch(异常类名 异常形式参数名) {异常处理语句组}
这里的try
语句用来启动异常处理机制,可能包含异常的语句,包括throw语句,调用可能出现异常的方法的语句,都应该包含在try语句中。
try后面至少有一个catch或一个finally。
当try语句块中某个语句在执行时产生了一个异常,此时被启动的异常处理机制会自动捕捉到它,然后流程自动跳过产生异常的语句后面的所有尚未被执行的语句,转至执行catch语句块。
catch语句捕捉抛出的异常并处理,被捕捉的异常必须与catch括号中定义的异常有关系:
异常对象所处的类与catch()中参数类先相同
异常对象所属类是catch()中参数类的子类
catch()中参数类是一个接口时,发生的异常对象类实现了这一接口
finally语句
不管在try代码块中是否发生异常事件,finally语句都会被执行。通常用于对一些资源做清洁工作,如关闭打开的文件。
多异常处理:
一个try块后面定义了若干个catch语句。
顺序判断每个catch,执行后推出当前方法,其余未被执行的catch被忽略。
如果所有catch都不满足,程序返回至调用该方法的上层方法。
如果所有方法都找不到合适的catch,此时由运行系统处理。通常为终止程序,推出JVM返回操作系统,打印异常信息。
catch块中要先catch子类异常,再catch父类异常。否则无法编译。