异常
异常的分类
Error(错误): 是程序无法处理的错误。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时、系统崩溃、虚拟机错误、动态链接失败等,这些错误无法恢复或者不可能捕捉,将导致应用程序中断,Error不需要捕捉。OutOfMemoryError\*Error。
Exception(异常) :是程序本身可以处理的异常。
- 受检查的异常(checked exceptions)粉色,其必须被 try{}catch语句块所捕获,或者在方法签名里通过throws子句声明.受检查的异常必须在编译时被捕捉处理,命名为 Checked Exception 是因为Java编译器要进行检查,Java虚拟机也要进行检查,以确保这个规则得到遵守。FileNotFoundException位于java.io.IOExcption下,当试图打开指定路径名表示的文件失败时,抛出此异常
- 运行时异常(runtime exceptions)绿色,需要程序员自己分析代码决定是否捕获和处理,比如 空指针,被0除..ClassCastException(当试图将对象强制转换为不是实例的子类时,抛出该异常),NullPointException(当应用程序试图在需要对象的地方使用null时,抛出异常),IndexOutOfBoundsException(指示某排索引超出范围时抛出),
异常处理方式
对于异常的处理方式有两种分别为:
- 捕捉 try{}catch{}finally{}
- 声明 throws
两者区别:
对于try{}catch{}finally{}而言,用户可能确定知道代码会出现相关的异常,把有可能出现问题的地方放到try中去执行,如果一旦出现异常,立刻终止当前代码的继续执行,转而去执行catch{}里面的内容。对于这类异常用户已经处理了,不会在向上抛出。
对于throws而言,一般使用在方法名的后面,使用throws关键字的时候,一般是开发者不确定出现什么异常或者出现异常的情况可能有多种。这时开发者在方法后面加throws关键字抛出相关的异常。对于调用该方法的其它开发者者必须捕获这个异常或者继续throws这个异常,把这个异常传递下去,自己不处理,交给其对应的父类去处理。
如果是多线程就用Thread.run()抛出,如果是单线程就用main()方法抛出。
throw关键字和throws关键字
- throw一般用于方法中,抛出用户自定义的异常如 throw new MyException("用户自定义异常")。
- throws是用在方法名的后面,通知使用该方法的人,当前方法有可能抛出异常。
throws和throw的区别(面试题)
throws
- 用在方法声明后面,跟的是异常类名
- 可以跟多个异常类名,用逗号隔开
- 表示抛出异常,由该方法的调用者来处理
- throws表示出现异常的一种可能性,并不一定会发生这些异常
throw
- 用在方法体内,跟的是异常对象名
- 只能抛出一个异常对象名
- 表示抛出异常,由方法体内的语句处理
- throw则是抛出了异常,执行throw则一定抛出了某种异常
使用异常的注意事项:
- 先捕获子类,再捕获基类
- 尽早抛出异常,同时对捕获的异常进行处理
- 可以根据实际的需求自定义异常类,这些异常类只要继承自Exception类即可
- 异常能处理就处理,不能处理就抛出
异常处理的执行顺序(针对try{}catch{}finally{}而言)
try(....){
}catch(....){
}finally(...){
}
t满足try的条件的执行try后面花括号的语句
不满足,被catch中语句捕获到的执行catch花括号的语句
没有被catch捕获到或者catch执行完毕后和try执行完毕后都要执行finally中的语句
一般来说finally中的方法都是会被执行的,其中finally中很大程度上用于资源的释放。
a、finally中的代码总是会执行吗?
答:no,
如果一个方法内在执行try{}语句之前就已经出现异常,会直接结束,那么finally语句指定不会执行了。因为它根本没有进入try语句中
如果在一个try语句中调用System.exit(0);方法,那么就会退出当前java虚拟机,那么finally也就没有执行的机会了。
b、finally在return之前执行还是在return之后执行?
答:很多人可能会说在return执行之前执行。我的答案是在return中间执行,是不是很特别,请按下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
正确答案是:1
首先程序在执行到try{}语句中的return方法后,就会先返回相应的值,并把相应的值存储在一个临时栈中去保存这个结果。这时临时栈中存储的值为1。但是程序不会立刻返回,转而回去执行finally中的方法,++x,在finally执行完后,方法全部执行完,这时会再次调用return方法,注意这时不在是返回值,而是告诉主调程序,被调程序已经执行完了,你可以接着去执行你主程序的其它方法了。但是请注意,此时返回的值还是原来保存在临时栈中的值1。
为了更好的理解这个问题,我们看下面的程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
正确答案是:2
这里仅仅需要注意的是在try{}语句中执行到return 1 会在临时栈中存储值为1的变量。接着回去执行finally里面的内容,这时执行finally中的return 2;方法,临时栈中的值就是变为 2,会覆盖原来临时栈中的值1.所以它的返回值为2。
return有两个作用:程序结束、更新返回值
c、finally方法是必须的吗?
不是,开发者可以根据自身的情况去决定是否使用finally关键字。
在异常处理中,若try中的代码可能产生多种异常则可以对应多个catch语句,若catch中的参数类型有父类子类关系,此时应该将子类放在前面,父类放在后面。