Java的异常处理可以让程序具有更好的容错性,程序更加健壮。当程序出现意外情况的时候,系统会自动生成一个Exception对象来通知程序,从而实现将“业务功能实现代码”和“错误处理代码”分离,提供更好的可读性。
一、异常类的继承体系
(1)在java中把异常当作对象来处理,并且定义一个基java.lang.Throwable作为所有异常的超类。在java API中定义很多异常类,java把所有的非正常情况分为两大类:错误(Error) 和异常(Exception)。
(2)Error错误
Error是程序无法处理的错误,一般指虚拟机相关的问题,如:系统崩溃、虚拟机出现错误、动态链接失败等,发生Error时,JVM一般会选择终止线程。
(3)Exception异常
Exception异常是程序本身可以处理的异常。 Exception异常通常包括RuntimeException异常和Checked Exception异常。
1)RuntimeException异常(不可查异常)
一般RuntimeException异常的发生是由程序的逻辑错误引起的,应该去找出错误修改程序,而不是去捕获RuntimeException异常.
Java的RuntimeException异常是一种unchecked Exception,即编译器不会检查程序是否对RuntimeException做了处理,在程序中不必捕获RuntimeException异常,也不必在方法体中声明抛出RuntimeException异常.
2)Checked Exception异常(可查异常)
所有继承自Exception的除了RuntimeException以外的都是Checked Exception异常。
只有java语言提供了checked 异常,其他语言并没有提供。Java认为Checked异常都是可以被处理的异常,所以java程序必须显示的处理Checked异常,如果程序不处理Checked异常,则无法通过编译。
二、异常处理机制
抛出异常:当程序出现意外情况的时候,系统会自动生成一个Exception对象并将异常对象交给java运行时环境,由运行系统负责寻找处置异常的代码并执行。异常对象中包含了异常的类型和异常出现时程序的状态等信息。
捕获异常:在抛出异常之后,系统将开始寻找合适的异常处理器。若是找到合适的异常处理器则执行异常处理,否则系统终止运行。
Java的异常处理主要依赖于try、catch、finally、throw、throws五个关键字
1、
(1)try-catch语句
try
{
业务实现代码
//如果发生了异常,那么异常之后的代码都不会被执行
}
catch(异常类型 异常变量名1)
{
异常处理代码
}
catch(异常类型 异常变量名2)
{
异常处理代码
}
try块后可以有多个catch块,每个catch块针对不同类型的异常提供给不同的处理方式,try中放得代码是可能发生异常的代码。在程序运行过程中若是发生异常则系统自动生成异常对象。Java运行环境试图寻找catch子句来捕获异常,如果有匹配的catch子句,则运行正常处理的代码。否则程序终止运行。
如果try块被执行一次,则try块后的catch块也被执行一次。
(2)在java中异常处理的完整语句(try、catch、finally)
try
{
业务实现代码
//如果发生了异常,那么异常之后的代码都不会被执行
}
catch(异常类型 异常变量名) //可有多个catch块,父类异常在子类异常之后
{
异常处理代码
}
finally
{
不管异常发生与否,总要执行的代码
}
(3)try、catch、finally的执行顺序
1)如果try块没有捕获到异常:程序会逐一执行try块中所有的代码,跳过catch块,执行fially语句块和它后面的语句;
2)try块捕获到异常:执行到try块里某一个语句出现异常,后面的语句不执行了,直接去寻找catch块里与抛出异常匹配的catch块,最后执行finally块和它后面的语句。
(4)try、catch、finally语法规则
(1)try块是必须的,catch、finally是可选的,但是try后至少要出现catch、finally其中的一个。也可以同时出现,多个catch块必须位于try块之后,finally块必须位于catch块之后。
(2)除了以下情况外,总将以fianlly块作为结束:
在try或者catch块中调用了System.exit(1)退出虚拟机的方法。
(3)尽量避免在fianlly块里使用return或throw等导致方法终止的语句。
在java程序执行try块、catch块遇到return或者throw语句,这两个语句都会导致方法立即结束,系统不会立即结束,会寻找异常处理流程中是否包含fianlly语句
fianlly不存在:立即执行return或者throw
fianlly存在:会执行fianlly块,只有执行完finally块后才会再调回try或者catch中执行return或者throw语句,如果此时finally里也有return或者throw,finally块已经终止了方法,那么系统不会跳回去执行try或者catch中的return或者throw了。
(4)异常处理可嵌套,可嵌套在try、catch、finally中的任何一个
2、抛出异常
(1)使用throws声明抛出异常
1)当前方法不知道如何处理这种类型的异常时,该异常应该有上一级调用者来处理,如果main方法也不知道如何处理,可以使用throws声明再次抛出异常,该异常交给JVM来处理。JVM处理异常的方法就是:打印异常跟踪栈信息,并中止程序运行。
2)throws声明抛出只能在方法签名中使用,可以声明抛出多个异常类,各个异常类之间用,隔开,格式如下:
throws ExceptionClass1,ExceptionClass2,,ExceptionClass3....
3)使用throws声明抛出有一个限制:在方法重写时遵循”两小”规则:子类方法中声明抛出的异常类型应该是父类方法声明中抛出的异常类型的子类或者同类。
(2)throws抛出异常的规则:
1)如果是不可查异常,即:Error和RuntimeException或者他们的子类,那么可以不使用throws关键字来声明要抛出的异常,编译成顺利通过,但运行时系统仍会抛出异常。
2)如果是可查异常:即checkedException,要么使用try-catch语句显示处理,要么使用throws子句声明将其抛出否则编译通不过。
3)仅仅是抛出了异常,方法的调用者必须处理或者再次将异常抛出。
(3)使用throw抛出异常
1)当程序出现异常时,系统会自动抛出异常,java允许程序可自行抛出异常,自动抛出异常使用throw语句完成。
很多时候系统是否要抛出异常,可能根据应用的业务需要来决定,如果程序中的数据与既定的业务需求不符合,那这就是一种异常(比如在测试一个方法时,期待结果与实际结果不符合)。这种由于与业务需求不一样产生的异常,必须由程序员来决定抛出,系统无法自行抛出这类异常。
2)如果需要在程序中自行抛出异常,应该使用throw语句,throw语句抛出的是一个异常对象,而且每次只能抛出一个异常对象。格式如下:
throw ExceptionInstance
3)不管是系统自动抛出的异常还是程序员使用throw语句抛出的异常,java环境对异常的处理是一样的。