-
catch
和finally
不能没有try
;
void go(){
Foo f = new Foo(); // 没有try
f.foof();
catch(FooException ex){}
}
-
try
和catch
之间不能有程序;
try{
x.doStuff();
}
int y = 44; //不能在这里放程序
catch(Exception ex){}
-
try
一定要有catch
或者finally
;
try{
x.doStuff();
}finally{ //这是合法的,但还是要注意第四条
//清理
}
- 只带有
finally
的try
必须要声明异常。
void go() throws FooException{
try{
x.doStuff();
}finally{
// 清理
}
}
不想处理异常时,just duck it。(duck在此处有声明的意思)
当调用有危险的方法时,编译器通常会要求你对这件事有所表示。通常我们的方式是将这个有危险的方法调用放入try/catch
块中。但是如果小小任性一下,我不愿意去用try/catch
去调用此方法,捕获危险,那该怎么做呢?
还是那句话:
不想处理异常时,just duck it。
只需要在调用这一危险方法的方法上声明(duck)一下异常就可以了。也就是说,你在调用方法中不想try/catch
,但是异常仍然还是存在,你不能坐视不管它带给调用方法的危险,所以调用方法只好throw
这个危险方法可能会throw的异常,就想踢皮球一样,该潜在异常会被“踢”到调用方法的声明中去。以下为例:
public void foo() throws ReallyBadException{
//调用有危险的方法doLaundry()
laundry.doLaundry();
//这里并没有用try/catch块来处理doLaundry()这个方法,
//这个存在异常的方法将异常“踢”给了调用方法foo()
}
但是如果以此深究下去,它最终会把这脚烂球踢给谁呢?
分析一下原理:
方法抛出异常的时候,方法会从栈上立即被取出,而异常会再度丢给栈上的方法,也就是调用方。如果调用方是个ducker,则此ducker也会从栈被取出,异常再度抛给此时栈上方的方法。
看下面这个最简单的终极踢球例子:
public class Washer{
Laundry laundry = new Laundry();
public void foo() throws ReallyBadException{
//调用有危险的方法doLaundry()
laundry.doLaundry();
}
public static void main(String [] args) throws ReallyBadException{
Washer washer = new Washer();
washer.foo();
}
}
方法们在栈中的顺序从顶至下依次为:doLaundry()
,foo()
, main()
方法的调用顺序是从栈顶开始,即
-
foo()
调用doLaundry()
时doLaundry()
会抛出ReallyBadException
-
doLaundry()
从栈上被取走,异常被“踢”给了foo()
-
main()
调用foo()
时foo()
抛出ReallyBadException
-
foo()
从栈上被取走,异常再次被“踢”,这次到了main()
这里 - 要知道,
main()
对于异常是没有什么责任感的。但如果main()
不throw
异常的话,虚拟机只好产生中断并报错了。
下面几句话帮助提升对异常处理的理解:
- 如果遇到编译器的检查异常,就必须把有风险的程序代码包在try/catch块中。
这句话是不对的,因为还有另一种方式,就是duck异常。
- 只有编译器的检查异常才会被捕获。
这句话是不对的,因为运行期间的异常也会被捕获。
- 如果方法声明可以抛出编译器检查的异常,则必须把抛出异常的程序代码包在try/catch块中。
这样做是不对的,其实只需要在方法中声明即可。这是另一种异常处理的方法。
网友评论