您的位置:首页 > 其它

Error Handling with Exceptions【4】

2007-11-19 17:04 295 查看
[今天单位内事情比较多,所以翻译的很少,另外我不知道这样作是否侵犯了什么利益,如果有的话请立即通知我,我会在第一时间删除所有内容,感谢]
Evenincasesinwhichtheexceptionisnotcaughtinthecurrentsetofcatchclauses,finallywillbeexecutedbeforetheexceptionhandlingmechanismcontinuesitssearchforahandleratthenexthigherlevel:

甚至假如说异常信息没有被当前的一组异常条件捕获的话,在异常处理机制在更高层寻找异常处理之前finally也会被执行。

importcom.bruceeckel.simpletest.*;


classFourExceptionextendsException{}


publicclassAlwaysFinally{

privatestaticTestmonitor=newTest();

publicstaticvoidmain(String[]args){

System.out.println("Enteringfirsttryblock");

try{

System.out.println("Enteringsecondtryblock");

try{

thrownewFourException();

}finally{

System.out.println("finallyin2ndtryblock");

}

}catch(FourExceptione){

System.err.println(

"CaughtFourExceptionin1sttryblock");

}finally{

System.err.println("finallyin1sttryblock");

}

monitor.expect(newString[]{

"Enteringfirsttryblock",

"Enteringsecondtryblock",

"finallyin2ndtryblock",

"CaughtFourExceptionin1sttryblock",

"finallyin1sttryblock"

});

}

}

Thefinallystatementwillalsobeexecutedinsituationsinwhichbreakandcontinuestatementsareinvolved.Notethat,alongwiththelabeledbreakandlabeledcontinue,finallyeliminatestheneedforagotostatementinJava.

在使用了break和continue的语句中finally语句也会被执行,需要说明的是,在Java中有了带标签的break和continue以及finally就不在需要goto语句了。

Pitfall:thelostexception

Unfortunately,there’saflawinJava’sexceptionimplementation.Althoughexceptionsareanindicationofacrisisinyourprogramandshouldneverbeignored,it’spossibleforanexceptiontosimplybelost.Thishappenswithaparticularconfigurationusingafinallyclause:

不幸的是在Java的异常中存在一个缺陷,尽管异常是程序中出现错误的提示,并且不可忽略,但是这里有可能会丢失一个异常。在特定的情况中使用了finally后就会发生。

importcom.bruceeckel.simpletest.*;


classVeryImportantExceptionextendsException{

publicStringtoString(){

return"Averyimportantexception!";

}

}


classHoHumExceptionextendsException{

publicStringtoString(){

return"Atrivialexception";

}

}


publicclassLostMessage{

privatestaticTestmonitor=newTest();

voidf()throwsVeryImportantException{

thrownewVeryImportantException();

}

voiddispose()throwsHoHumException{

thrownewHoHumException();

}

publicstaticvoidmain(String[]args)throwsException{

LostMessagelm=newLostMessage();

try{

lm.f();

}finally{

lm.dispose();

}

monitor.expect(newString[]{

"Exceptioninthread/"main/"Atrivialexception",

"/tatLostMessage.dispose(LostMessage.java:24)",

"/tatLostMessage.main(LostMessage.java:31)"

});}

}

Youcanseethatthere’snoevidenceoftheVeryImportantException,whichissimplyreplacedbytheHoHumExceptioninthefinallyclause.Thisisaratherseriouspitfall,sinceitmeansthatanexceptioncanbecompletelylost,andinafarmoresubtleanddifficult-to-detectfashionthantheprecedingexample.Incontrast,C++treatsthesituationinwhichasecondexceptionisthrownbeforethefirstoneishandledasadireprogrammingerror.PerhapsafutureversionofJavawillrepairthisproblem(ontheotherhand,youwilltypicallywrapanymethodthatthrowsanexception,suchasdispose(),insideatry-catchclause).

你可以看到关于VeryImportException异常一点痕迹都没有,它在finally中轻而易举的被HoHumException代替了,这是一个很严重的缺陷,因为这意味着一个异常信息可能会被整个丢掉,而实际上要比上面的例子展示的更加微妙更加的难以发现。相反在C++中对于第一个异常还没有被捕获就抛出了第二个异常这种情况视为严重的程序错误。相信不就的版本中Java就会修复此问题。换一种说法,你应该将诸如dispose()这样的方法放到try-catch的子句中。[在Version:6.0.1GA中测试时编译期间就提示错误:SeverityandDescriptionPathResourceLocationCreationTimeIdUnhandledexceptiontypeVeryImportantException,所以应该已经修复了此问题]

Exceptionrestrictions

Whenyouoverrideamethod,youcanthrowonlytheexceptionsthathavebeenspecifiedinthebase-classversionofthemethod.Thisisausefulrestriction,sinceitmeansthatcodethatworkswiththebaseclasswillautomaticallyworkwithanyobjectderivedfromthebaseclass(afundamentalOOPconcept,ofcourse),includingexceptions.

当你覆写方法的时候,你只能抛出基类中该方法抛出的异常,这个限制是很有用的,因为这意味着能够使用基类对象的代码肯定也可以是与和这个基类的派生类的对象,这是一个基本的面向对象的原则当然异常也不能例外。

Thisexampledemonstratesthekindsofrestrictionsimposed(atcompiletime)forexceptions:

下面的例子展示了在异常上面增加限制条件:

//:c09:StormyInning.java

//Overriddenmethodsmaythrowonlytheexceptions

//specifiedintheirbase-classversions,orexceptions

//derivedfromthebase-classexceptions.


classBaseballExceptionextendsException{}

classFoulextendsBaseballException{}

classStrikeextendsBaseballException{}


abstractclassInning{

publicInning()throwsBaseballException{}

publicvoidevent()throwsBaseballException{

//Doesn'tactuallyhavetothrowanything

}

publicabstractvoidatBat()throwsStrike,Foul;

publicvoidwalk(){}//Throwsnocheckedexceptions

}


classStormExceptionextendsException{}

classRainedOutextendsStormException{}

classPopFoulextendsFoul{}


interfaceStorm{

publicvoidevent()throwsRainedOut;

publicvoidrainHard()throwsRainedOut;

}


publicclassStormyInningextendsInningimplementsStorm{

//OKtoaddnewexceptionsforconstructors,butyou

//mustdealwiththebaseconstructorexceptions:

publicStormyInning()

throwsRainedOut,BaseballException{}

publicStormyInning(Strings)

throwsFoul,BaseballException{}

//Regularmethodsmustconformtobaseclass:

//!voidwalk()throwsPopFoul{}//Compileerror

//InterfaceCANNOTaddexceptionstoexisting

//methodsfromthebaseclass:

//!publicvoidevent()throwsRainedOut{}

//Ifthemethoddoesn'talreadyexistinthe

//baseclass,theexceptionisOK:

publicvoidrainHard()throwsRainedOut{}

//Youcanchoosetonotthrowanyexceptions,

//evenifthebaseversiondoes:

publicvoidevent(){}

//Overriddenmethodscanthrowinheritedexceptions:

publicvoidatBat()throwsPopFoul{}

publicstaticvoidmain(String[]args){

try{

StormyInningsi=newStormyInning();

si.atBat();

}catch(PopFoule){

System.err.println("Popfoul");

}catch(RainedOute){

System.err.println("Rainedout");

}catch(BaseballExceptione){

System.err.println("Genericbaseballexception");

}

//Strikenotthrowninderivedversion.

try{

//Whathappensifyouupcast?

Inningi=newStormyInning();

i.atBat();

//Youmustcatchtheexceptionsfromthe

//base-classversionofthemethod:

}catch(Strikee){

System.err.println("Strike");

}catch(Foule){

System.err.println("Foul");

}catch(RainedOute){

System.err.println("Rainedout");

}catch(BaseballExceptione){

System.err.println("Genericbaseballexception");

}

}

}

InInning,youcanseethatboththeconstructorandtheevent()methodsaytheywillthrowanexception,buttheyneverdo.Thisislegalbecauseitallowsyoutoforcetheusertocatchanyexceptionsthatmightbeaddedinoverriddenversionsofevent().Thesameideaholdsforabstractmethods,asseeninatBat().

在Inning类中,你可以看到构造方法和event()方法都声明为会抛出异常,但是并没有在实现中这么作。这是合法的因为这样就强制用户去捕获这个异常,因为在event()的覆写的方法中可能会使用。同理在atBat()中也使用到了这个办法。

TheinterfaceStormisinterestingbecauseitcontainsonemethod(event())thatisdefinedinInning,andonemethodthatisn’t.Bothmethodsthrowanewtypeofexception,RainedOut.WhenStormyInningextendsInningandimplementsStorm,you’llseethattheevent()methodinStormcannotchangetheexceptioninterfaceofevent()inInning.Again,thismakessensebecauseotherwiseyou’dneverknowifyouwerecatchingthecorrectthingwhenworkingwiththebaseclass.Ofcourse,ifamethoddescribedinaninterfaceisnotinthebaseclass,suchasrainHard(),thenthere’snoproblemifitthrowsexceptions.

Storm这个接口比较有意思,因为它包含了一个已经在Inning类中定义了的方法event(),另外一个方法不是。两个方法都抛出了一个新的Exception类型RainedOut。当StormyInning类继承了Inning并且实现了Storm接口。你可以看到Storm中event()的方法改变不了Inning中event()的异常信息。它的意思就是说当你使用基类工作的时候你就不知道是否捕获了正确的异常信息。当然如果一个接口中的方法并没有在基类中声明,它抛出异常信息是没有任何问题的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: