当前位置: 首页 > 后端技术 > PHP

Java异常分析

时间:2023-03-29 16:21:26 PHP

基本概念Java使用异常来提供一致的错误报告模型;错误处理可以集中处理;任务代码与异常代码分离,易于理解和维护。虽然异常处理理论有终止模型和恢复模型两种,但是恢复模型很难做到优雅,∴不实用。在实践中,每个人都转而使用终止模型代码。抛出异常后会发生两件事:①使用new在堆上创建一个异常对象;②异常处理机制开始接管进程(当前执行进程终止)标准异常类有两个ctor:①defaultctor;②字符串参数的ctorThrowable是异常类型catch异常的根类,try中抛出子类异常,但是catch基类异常也可以,但是如果catch子类异常和基类异常子句同时存在时候,基类的catch子句应该放在后面,避免出现“屏蔽”现象。抛出异常+捕获异常并抛出异常(throw):if(t==null)thrownewNullPointerException();//在堆上创建异常对象new12Catchexception(try+catch):try{...}catch(Type1id1){//处理Type1类型的异常代码}catch(Type2id2){//HandletheexceptioncodeofType2type}1234567虽然上面的id1和id2在异常处理代码中可以不用,但是必须定义。当异常发生时,异常机制会搜索第一个参数匹配异常类型的catch子句,进入创建自定义异常Createacustomexceptionclasswithoutaparameterctor://customexceptionclass(defaultctor)classSimpleExceptionextends例外{}-------------------------------------//客户端代码publicclassUseException{publicvoidfunthrowsSimpleException{System.out.println("ThrowSimpleExceptionfromfun");抛出新的SimpleException();}publicstaticvoidmain(String[]args){UseException用户=newUseException();尝试{用户。乐趣();}catch(SimpleExceptione){System.出去。println("抓到它了!");}}}--------------------------------------------------------------//OutputThrowSimpleExceptionfromfunCaughtit!123456789101112131415161718192021222324Createacustomexceptionclasswithparameterctor//自定义异常类(带参数ctor)classMyExceptionextendsException{publicMyException(){}publicMyException()supms{msg);}}----------------------------------------------------------//客户端代码publicclassUseException{publicclassstaticvoidf()throwsMyException{System.out.println("ThrowingMyExceptionfromf()")thrownew我的异常();}publicstaticvoidg()throwsMyException{System.out.println("ThrowingMyExceptionfromg()")thrownewMyException("Originateding()");}publibstaticvoidmain(String[]args){try{f();}catch(MyExceptione){e.printStackTrace(System.out);}尝试{g();}catch(MyExceptione){e.printStackTrace(System.out);}}}----------------------------------------------------------//输出ThrowingMyExceptionfromf()MyExceptionat...在...ThrowingMyExceptionfromg()MyException:Originateding()//ThisistheString创建异常类型时传入的参数at...at...1234567891011121314151617181920212223242526272829303132334353637383940414243444Catchallexceptions(try...5Exceptione){//填写异常的基类,catch子句一般放在最后。..}12345异常类型持有方法:-StringgetMessage()-StringgetLocalizedMessage()-StringtoString()voidprintStackTrace()voidprintStackTrace(PrintStream)voidprintStackTrace(javo.io.PrintWriter)注意:每个方法从下到上提供了比上一个更多的异常信息!StacktraceprintStackTrace()方法提供的stacktrace信息可以通过getStackTrace()方法获取,例如:))System.out.println(ste.getMethodName());}123456这里使用了getMethodName()方法来给出异常堆栈跟踪的方向法号!重新抛出异常try{...}catch(Exceptione){throwe;//重新抛出异常!}12345如果异常只是简单的重新抛出,那么printStackTrace()会显示原异常抛出点的调用栈信息,而不是重新抛出点信息。要更正此信息,您可以使用fillInStackTrace()方法://这一行成为异常发生的新地方!}12345Exceptionchain异常链:捕获一个异常后抛出另一个异常,希望能保存原来的异常信息!解决方案:\1。给异常的ctor\2加上cause参数。使用initCause()方法注意:在Throwable子类中,只有三个基本异常类提供了参数引发的ctor(Error,Exception,RuntimeException),其他情况只能依赖initCause()方法,例如:classDynamicFieldsException扩展异常{}publicObjectsetField(Stringid,Objectvalue)throwsDynamicFieldsException{if(value==null){DynamicFieldsExceptiondfe=newDynamicFieldsException();dfe。initCause(新NullPointerException());扔dfe;}对象结果=空;尝试{结果=getField(id);}catch(NoSuchFieldExceptione){thrownewRuntimeException(e);:程序员一般关心Exception基类型的异常。从图中可以看出Error,RuntimeExceptionion称为“UncheckedException”,即不检查异常,程序员不需要编写异常处理代码。这个自动捕获,如果RuntimeException等Unchecked异常没有被捕获直接进入main(),程序会在退出前自动检查。调用异常的printStackTrace()方法使用finally清理try{...}catch(...){...}finally{//finally子句会一直执行!!!...}1234567何时使用:-当您需要将内存之外的资源(例如:文件句柄、网络连接、外部世界中的开关)恢复到原始状态时!try{...}catch(...){...}finally{//finally子句总是会被执行!!!开关关闭();//总有一个开关需要最后关掉!}1234567使用finallypublicstaticvoidfunc(inti){try{if(i==1)return;如果(我==2)返回;}finally{print("执行清理!");//即使上面有很多return,但是这句话一定要执行}}123456789101112finally有缺点:两种情况下使用finally会导致异常丢失!在处理前一个异常之前抛出下一个异常//ExceptionclassclassVeryImportantExceptionextendsException{publicStringtoString(){return"一个非常重要的异常!";}}classHoHumExceptionextendsException{publicStringtoString(){return"Atrivialexception!";}}----------------------------------------------------------------//ClientusingexceptionpublicclassLostMessage{voidf()抛出VeryImportantException{抛出新的VeryImportantException();}voiddispose()throwsHoHumException{thrownewHoHumException();}publicstaticvoidmain(String[]args){try{LostMessagelm=(newLostMessage);尝试{lm.f();}最后{lm.dispose();//最后只有异常才会生效,lm.f()抛出的异常丢失!}}catch(异常e){System.出去。打印(e);}}}------------------------------------------------------------------//输出一个微不足道的异常!123456789101112131415161718192021222324252627282930313233343536373839returnpublicstaticvoidinfinallyclausemain(String[]args){try{thrownewRuntimeException();}最后{返回;//这样会覆盖所有抛出的异常}}1234567继承基类,实现接口时的异常限制//ExceptionclassclassAextendsException{}classA1extendsA{}classA2extendsA{}classA1_1extendsA1{}B类扩展异常{}B1类扩展B{}--------------------------------------------//用过的异常类的基类abstractclassBase{publicBase()throwsA{}publicvoidevent()throwsA{}//(1)publicabstractvoidatBatthrowsA1,A2;publicvoidwalk(){}}----------------------------------------------//使用异常类的接口interfaceInterf{publicvoidevent()throwsB1;publicvoidrainHard()throwsB1;}----------------------------------------------//继承基类并实现接口的客户端类publicclassExtextendsBaseimplementsInterf{publicExt()throwsB1,A{}//(2)publicExt(Strings)throwsA1,A{}//(2)publicvoidwalk()throwsA1_1{}//(3)编译错误!publicvoidrainHard()throwsB1{}//(4)publicvoidevent(){}//(5)publicvoidatBat()throwsA1_1{}//(6)publicstaticvoidmain(String[]args){尝试{Extext=newExt();ext.atBat();}catch(A1_1e){...}catch(B1e){...}catch(Ae){...}try{Basebase=新分机();ext.atBat();}catch(A2e){//这里的catch必须根据Base中函数抛出的异常来写...}catch(A1e){...}catch(B1e){...}catch(A){...}}}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162上面的例子可以总结如下:【注意对应数字标号】(1)基类的构造器或者方法声明了抛出异常,但Infact,no,hereisequivalentto为继承类编写异常抛出规范,并安装该规范以在子类实现时抛出异常。抛任何异常不管基类ctor抛出的异常(3)基类函数不抛异常,派生类改写时不能盲目抛!(4)完全遵守基类的抛出,一般情况下(5)如果基类函数抛出异常,派生类改写时不抛也可以(6)派生类改写时抛出的异常基类函数可以是基类如何在类函数抛出异常的子类型构造函数中写异常对于在构造阶段可能抛出异常并需要清理的类,安全的方法是使用嵌套的try子句:即在创建之后需要清理的对象,马上进入一个try-finally块,例如:下面例子中要特别注意ctor中文件句柄的close的合理位置!//需要清理的对象类classInputFile{privateBufferedReaderin;InputFile(Stringfname)throwsException{//构造函数!尝试{in=newBufferedReader(newFileReader(fname));//其他可能抛出异常的代码放这里}catch(FileNotFoundExceptione){//如果上面的FileReader异常,会抛出FileNotFoundException,去这里在这个分支中,System.out.println("Couldnotopen"+fname);扔e;}catch(Exceptione){//走到这里其实说明in对象已经构造成功,这里是try{in.close()那一定是in.close();//注意这里的关闭动作是通过单独尝试来保证的}catch(IOExceptione2){System.out.println("in.close()unsuccessful");}扔e;}finally{//注意这里in.close()不要关闭,因为如果try中BufferedReader的构造失败,此时in对象还没有生成成功,就不用说close()了!}}StringgetLine(){Strings;尝试{s=in.readLine();}catch(IOExceptione){System.出去。println("readLine()不成功!");s="失败";}返回s;}voidcleanup(){//提供手动关闭文件句柄的操作函数try{in.close();}catch(IOExceptione){System.out.println("in.close()失败!");}}}---------------------------------------------------//客户端代码publicclassCleanup{publicstaticvoidmain(String[]args){try{InputFilein=newInputFile("Cleanup.java");try{//上面的InputFile构造完成后马上进入try-finally子句!字符串s="";诠释我=1;while((s=in.getLine())!=null)System.出去。println(""+i+++":"+s);}catch(Exceptione){e.printStackTrace(System.out);}finally{//finally必须保证in能正常cleanup()!在.cleanup();}}catch(Exceptione){System.out.println("InputFilectorfailed!");}}//endmain()}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869while((s=in.getLine())!=null)System.out.println(""+i+++":"+s);}catch(Exceptione){e.printStackTrace(System.out);}finally{//finally必须保证in能正常清理()!在.cleanup();}}catch(Exceptione){System.out.println("InputFilectorfailed!");}}//结束main()}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869