初学Java-异常
这一节最最要的几个概念是try,catch,finally,还有异常类和异常处理的过程。
1:java虚拟机的方法调用栈
java虚拟机的方法调用栈是用来跟踪每个线程中的一系列的方法调用过程的。该堆栈保存了每个调用方法的本地信息。对于java应用程序的主线程,堆栈底部是程序的入口方法main()。当一个新方法被调用时,java虚拟机就把描述该方法的堆栈结构压入栈顶,位于栈顶的方法为当前正在执行的方法(c,c++也是这样干的)。在下面图中,main()函数中调用methodB()方法,methodB()方法中调用methodA()方法,主线程的方法堆栈如下所示
如果方法中抛出异常,则有以下两种方法处理:一是在当前方法中通过try,catch语句捕获并处理异常;二是在方法的声明出通过throws语句声明抛出异常(这个throws和throw后面要讲)
当一个方法正常执行完毕后,java虚拟机会从调用栈中弹出该方法的栈结构,然后继续处理前一个方法。如果在执行方法的过程中抛出异常,则java虚拟机必须找到能捕获该异常的catch代码块。它首先检查当前方法是否存在这样的catch代码块,如果存在,那么就执行该catch代码块;否则,java虚拟机会从堆栈中弹出该方法的栈结构,继续道前一个方法中查找合适的catch代码块。
例如,当methodA()方法抛出SpecialException(自己定义的异常类)时,若果methodA()方法中有catch(SpecialException)代码块,那么它就会跳到这地方执行,若果没有,它就会把methodA()方法的堆栈结构从堆栈中弹出(也意味着methodA方法不会继续执行了),然后去methodB方法中去查找有没有catch(SpecialException)代码块,若果有,那么捕获该异常,如果没有并且声明抛出该异常(throws SpecialException),就把methodB()方法的堆栈结构才能够堆栈中弹出,去main方法中查找有没有catch(SpecialException)代码块,如果没有,就会打印异常信息并且终止应用程序的运行。
2:try……catch代码块
a:异常的抛出要在try模块中,同样,异常的捕获是在catch模块中,一个try块后面可跟0个或多个catch代码块,因为并不是所有的try代码块中都会抛出异常
b:finally代码块,是任何情况下都必须执行的代码。不管try代码块中是否抛出异常,都会执行finally代码块。即若try代码块没有抛出异常,那么执行完try代码块后就会执行紧跟着的finally代码块;若抛出异常,那么若是有相应的捕获语句,就会先执行catch代码块再执行finally代码块,若没有捕获的catch代码块,就会执行finally代码块然后弹出方法的堆栈结构。
c:try代码块不能脱离catch代码块或者finally代码块而单独存在。try代码块后面至少要有一个catch代码块或者finally代码块。
d:try代码块后面可以有零个或者多个catch代码块,还可以有0个或者之多一个finnally代码块。如果catch代码块和finally代码块并存,finally代码块必须跟在catch代码块后面
e:try代码块后面可以只跟finally代码块
f:当try代码块后面有多个catch代码块时,java虚拟机会把实际抛出的异常对象依次和各个catch代码块声明的异常类型匹配,如果异常对象为某个异常类型或者其子类的实例,就执行这个catch代码块,而不会再执行其他的catch代码块。
3:throw和throws关键字
throws子句跟在方法的后面,声明方法可能会抛出的异常类型,原因是这个方法没有能力处理这种异常。
throw语句用来抛出异常,用throw语句抛出的异常对象必须是java.lang.Throwable类或其子类的实例。
如果一个方法可能出现受检查异常,要么用try,catch语句捕获,要么用throws语句声明将它抛出,否则会导致编译错误。
throw语句后面不允许跟其他语句,因为这些语句永远不会被执行
4:异常流程的运行过程
a:finally语句不被执行的唯一情况是先执行了用于终止程序的System.exit()方法。
b:return语句用于退出本方法,在执行try或者catch代码块中的return 语句时,加入有finally代码块,会先执行finally代码块,然后再返回到return语句执行
c:finally代码块虽然在return 语句之前被执行,但finally代码块不能通过重新给变量赋值的方式来改变return语句的返回值
d:建议不要在finally代码块中使用return语句,因为它可能导致以下两种异常情况的发生:一是覆盖try或者catch代码块中的return语句,第二种是丢失异常。
5:java异常类
所有异常类的祖先类都是java.lang.Throwable,它的实例表示具体的异常对象,可以通过throw方法抛出。Throwable提供了访问控制异常信息的一些方法,常用的方法包括:getMessage()和printStackTrace()。
java.lang
类 Throwable
java.lang.Object
java.lang.Throwable
- 所有已实现的接口:
- Serializable
- 直接已知子类:
- Error, Exception
- Error类是表示依靠程序本身无法恢复的严重错误,比如内存空间不足或者java虚拟机的方法调用栈溢出
- Exception类表示程序本书可以处理的异常。可以分为两种类型:运行时异常和受检查异常
- RuntimeException类及其子类都被称为运行时异常,这种异常的特点是java编译器不会检查它,也就是说,当程序中可能出现这种异常时,即使没有用try,catch语句捕获它,也没有用throws语句声明将异常抛出,还是会通过编译。当程序在运行过程中出现了这种异常时,就会导致程序异常终止。
- 受检查异常时指除了RuntimeException及其子类意外的Exception类,这种异常的特点是java编译器会检查它,当程序出现这种异常时,要么用try,catch代码块捕获,要么用throws声明将异常抛出,否则编译错误。