目录
一、java异常机制介绍和Throwable类
先看下面这张体系图,所有的异常都继承自Throwable类,主要有两个子类Error和Exception
二、Error
是程序无法处理的错误,表示运行应用程序中较严重问题,这种严重问题无法捕获
三、Exception
Exception 是是程序本身可以处理的异常,主要分为两类
- 编异异常:检查型异常(IOException、SQLException、自定义异常)
- 运行时异常:非检查型异常(RuntimeException)
1、编译异常
如果程序中出现此类异常,比如说IOException,必须对该异常进行处理,否则编译不通过。在程序中,通常不会自定义该类异常,而是直接使用系统提供的异常类。
2、运行时异常
RuntimeException类极其子类表示JVM在运行期间可能出现的错误。比如说试图使用空值对象的引用(NullPointerException)、数组下标越界(ArrayIndexOutBoundException)。此类异常属于不可查异常,一般是由程序逻辑错误引起的,在程序中可以选择捕获处理,也可以不处理。
四、异常处理机制
1、抛出异常、处理异常
- 抛出异常
任何代码都可以通过throw关键词抛出异常
- 捕获异常
一旦方法抛出异常,系统自动根据该异常对象寻找合适异常处理器(Exception Handler)来处理该异常。所谓合适类型的异常处理器指的是异常对象类型和异常处理器类型一致
对于不同的异常,java采用不同的异常处理方式:
- 运行异常将由系统自动抛出,应用本身可以选择处理或者忽略该异常。
- 对于方法中产生的Error,该异常一旦发生JVM将自行处理该异常,因此java允许应用不抛出此类异常。
- 对于所有的可查异常,必须进行捕获或者抛出该方法之外交给上层处理。也就是当一个方法存在异常时,要么使用try-catch捕获,要么使用该方法使用throws将该异常抛调用该方法的上层调用者。
2、try-catch-finally
try代码块:用于捕获异常。其后可以接零个或者多个catch块。如果没有catch块,后必须跟finally块,来完成资源释放等操作,另外建议不要在finally中使用return,不用尝试通过catch来控制代码流程。
catch代码块:用于捕获异常,并在其中处理异常。
finally代码块:无论是否捕获异常,finally代码总会被执行。如果try代码块或者catch代码块中有return语句时,finally代码块将在方法返回前被执行。注意以下几种情况,finally代码块不会被执行
- 在前边的代码中使用System.exit()退出应用。
- 程序所在的线程死亡或者cpu关闭
- 如果在finally代码块中的操作又产生异常,则该finally代码块不能完全执行结束,同时该异常会覆盖前边抛出的异常。
try捕获到异常时
如果没有与之匹配的catch子句,则该异常交给JVM处理,后面代码不会再执行
如果有catch子句,将执行catch子句的内容,再执行后续代码
如果有finnally,无论有没有发生异常,无论是否catch了异常,都会再执行finally代码
try {
//可能产生的异常的代码区,也成为监控区
}catch (ExceptionType1 e) {
//捕获并处理try抛出异常类型为ExceptionType1的异常
}catch(ExceptionType2 e) {
//捕获并处理try抛出异常类型为ExceptionType2的异常
}finally{
//无论是出现异常,finally块中的代码都将被执行
}
3、通过throws直接抛出异常
(1)throws可以用在方法上来抛出异常,把异常交给该方法的调用者来处理,其实就是自己不想对异常做出任何的处理,告诉别人自己可能出现的异常,交给别人处理,让别人处理
(2)有个关键字,throw和throws非常相似,用法容易混淆
throw:是用来抛出一个具体的异常类型,用在方法中,后面跟的是异常对象名
try {
//假设会产生一个运行时异常,下标越界
}catch (IndexOutOfBoundsException e) {
//这里可以不处理这个异常,通过throw来抛出
throw e;
//throw new IndexOutOfBoundsException();
}
throws:用在方法声明后面,跟的是异常类名,而且可以是多个异常
当一个方法内部抛出了非运行时异常时,这个方法上一定要throws这个异常,当然如果内部没有抛出这个异常,方法上依然可以加上throws某某异常,不一定非要内部有
五、自定义异常
(注:属于编译时异常,需要捕获)
在Java中要想创建自定义异常,需要继承Throwable或者他的子类Exception
然后在自定义异常类中的构造方法里,直接使用super调用父类对应的构造方法即可
下面代码是自定义了一个异常,并测试了抛出,捕获异常的代码
public class TestException extends Throwable/* 继承Exception也行 */ {
public static void main(String[] args) {
try {
test();
} catch (TestException e) {
System.out.println("catch块:" + e);
// 这块可以不处理,把他包装一下,转成运行时异常,写法如下两行
/*RuntimeException re = new RuntimeException(e);
throw re;*/
} finally {
System.out.println("finally块");
}
System.out.println("最后还执行了这个");
}
private static void test() throws TestException {
throw new TestException("这个异常时是定义的");
}
// 无参构造方法
public TestException() {
super();
}
// 有参的构造方法
public TestException(String message) {
super(message);
}
// 用指定的详细信息和原因构造一个新的异常
public TestException(String message, Throwable cause) {
super(message, cause);
}
// 用指定原因构造一个新的异常
public TestException(Throwable cause) {
super(cause);
}
}
执行结果是
catch块:com.myProject.TestException: 这个异常是自定义的
finally块
最后还执行了这个