解析Java中所有错误和异常的父类java.lang.Throwable
在java语言中,错误类的基类是java.lang.Error,异常类的基类是java.lang.Exception。
1)相同点:java.lang.Error和java.lang.Exception都是java.lang.Throwable的子类,因此java.lang.Error和java.lang.Exception自身及其子类都可以作为throw的使用对象,如:thrownewMyError();和thrownewMyException();其中,MyError类是java.lang.Error的子类,MyException类是java.lang.Exception的子类。
2)不同点:java.lang.Error自身及其子类不需要try-catch语句的支持,可在任何时候将返回方法,如下面的方法定义:
publicStringmyMethod(){ thrownewMyError(); }
其中MyError类是java.lang.Error类的子类。
java.lang.Exception自身及其子类需要try-catch语句的支持,如下的方法定义是错误的:
publicStringmyMethod(){ thrownewMyException(); }
正确的方法定义如下:
publicStringmyMethod()throwsMyException{ thrownewMyException(); }
其中MyException类是java.lang.Exception的子类。
JAVA异常是在java程序运行的时候遇到非正常的情况而创建的对象,它封装了异常信息,java异常的根类为java.lang.Throwable,整个类有两个直接子类java.lang.Error和java.lang.Exception.Error是程序本身无法恢复的严重错误.Exception则表示可以被程序捕获并处理的异常错误.JVM用方法调用栈来跟踪每个线程中一系列的方法调用过程,该栈保存了每个调用方法的本地信息.对于独立的JAVA程序,可以一直到该程序的main方法.当一个新方法被调用的时候,JVM把描述该方法的栈结构置入栈顶,位于栈顶的方法为正确执行的方法.当一个JAVA方法正常执行完毕,JVM回从调用栈中弹处该方法的栈结构,然后继续处理前一个方法.如果java方法在执行代码的过程中抛出异常,JVM必须找到能捕获异常的catch块代码.它首先查看当前方法是否存在这样的catch代码块,如果存在就执行该catch代码块,否则JVM回调用栈中弹处该方法的栈结构,继续到前一个方法中查找合适的catch代码块.最后如果JVM向上追到了main()方法,也就是一直把异常抛给了main()方法,仍然没有找到该异常处理的代码块,该线程就会异常终止,如果该线程是主线程,应用程序也随之终止,此时JVM将把异常直接抛给用户,在用户终端上会看到原始的异常信息.
Java.lang.throwable源代码解析
packagejava.lang; importjava.io.*; /** * *Throwable是所有Error和Exceptiong的父类 *注意它有四个构造函数: *Throwable() *Throwable(Stringmessage) *Throwable(Throwablecause) *Throwable(Stringmessage,Throwablecause) * */ publicclassThrowableimplementsSerializable{ privatestaticfinallongserialVersionUID=-3042686055658047285L; /** *Nativecodesavessomeindicationofthestackbacktraceinthisslot. */ privatetransientObjectbacktrace; /** *描述此异常的信息 */ privateStringdetailMessage; /** *表示当前异常由那个Throwable引起 *如果为null表示此异常不是由其他Throwable引起的 *如果此对象与自己相同,表明此异常的起因对象还没有被初始化 */ privateThrowablecause=this; /** *描述异常轨迹的数组 */ privateStackTraceElement[]stackTrace; /** *构造函数,起因对象没有被初始化可以在以后使用initCause进行初始化 *fillInStackTrace可以用来初始化它的异常轨迹的数组 */ publicThrowable(){ fillInStackTrace(); } /** *构造函数 */ publicThrowable(Stringmessage){ //填充异常轨迹数组 fillInStackTrace(); //初始化异常描述信息 detailMessage=message; } /** *构造函数,cause表示起因对象 */ publicThrowable(Stringmessage,Throwablecause){ fillInStackTrace(); detailMessage=message; this.cause=cause; } /** *构造函数 */ publicThrowable(Throwablecause){ fillInStackTrace(); detailMessage=(cause==null?null:cause.toString()); this.cause=cause; } /** *获取详细信息 */ publicStringgetMessage(){ returndetailMessage; } /** *获取详细信息 */ publicStringgetLocalizedMessage(){ returngetMessage(); } /** *获取起因对象 */ publicThrowablegetCause(){ return(cause==this?null:cause); } /** *初始化起因对象,这个方法只能在未被初始化的情况下调用一次 */ publicsynchronizedThrowableinitCause(Throwablecause){ //如果不是未初始化状态则抛出异常 if(this.cause!=this) thrownewIllegalStateException("Can'toverwritecause"); //要设置的起因对象与自身相等则抛出异常 if(cause==this) thrownewIllegalArgumentException("Self-causationnotpermitted"); //设置起因对象 this.cause=cause; //返回设置的起因的对象 returnthis; } /** *字符串表示形式 */ publicStringtoString(){ Strings=getClass().getName(); Stringmessage=getLocalizedMessage(); return(message!=null)?(s+":"+message):s; } /** *打印出错误轨迹 */ publicvoidprintStackTrace(){ printStackTrace(System.err); } /** *打印出错误轨迹 */ publicvoidprintStackTrace(PrintStreams){ synchronized(s){ //调用当前对象的toString方法 s.println(this); //获取异常轨迹数组 StackTraceElement[]trace=getOurStackTrace(); //打印出每个元素的字符串表示 for(inti=0;i<trace.length;i++) s.println("\tat"+trace[i]); //获取起因对象 ThrowableourCause=getCause(); //递归的打印出起因对象的信息 if(ourCause!=null) ourCause.printStackTraceAsCause(s,trace); } } /** *打印起因对象的信息 *@params打印的流 *@paramcausedTrace有此对象引起的异常的异常轨迹 */ privatevoidprintStackTraceAsCause(PrintStreams, StackTraceElement[]causedTrace) { //获得当前的异常轨迹 StackTraceElement[]trace=getOurStackTrace(); //m为当前异常轨迹数组的最后一个元素位置, //n为当前对象引起的异常的异常轨迹数组的最后一个元素 intm=trace.length-1,n=causedTrace.length-1; //分别从两个数组的后面做循环,如果相等则一直循环,直到不等或数组到头 while(m>=0&&n>=0&&trace[m].equals(causedTrace[n])){ m--;n--; } //相同的个数 intframesInCommon=trace.length-1-m; //打印出不同的错误轨迹 s.println("Causedby:"+this); for(inti=0;i<=m;i++) s.println("\tat"+trace[i]); //如果有相同的则打印出相同的个数 if(framesInCommon!=0) s.println("\t..."+framesInCommon+"more"); //获得此对象的起因对象,并递归打印出信息 ThrowableourCause=getCause(); if(ourCause!=null) ourCause.printStackTraceAsCause(s,trace); } /** *打印出错误轨迹 */ publicvoidprintStackTrace(PrintWriters){ synchronized(s){ s.println(this); StackTraceElement[]trace=getOurStackTrace(); for(inti=0;i<trace.length;i++) s.println("\tat"+trace[i]); ThrowableourCause=getCause(); if(ourCause!=null) ourCause.printStackTraceAsCause(s,trace); } } /** *打印起因对象的信息 */ privatevoidprintStackTraceAsCause(PrintWriters, StackTraceElement[]causedTrace) { //assertThread.holdsLock(s); //Computenumberofframesincommonbetweenthisandcaused StackTraceElement[]trace=getOurStackTrace(); intm=trace.length-1,n=causedTrace.length-1; while(m>=0&&n>=0&&trace[m].equals(causedTrace[n])){ m--;n--; } intframesInCommon=trace.length-1-m; s.println("Causedby:"+this); for(inti=0;i<=m;i++) s.println("\tat"+trace[i]); if(framesInCommon!=0) s.println("\t..."+framesInCommon+"more"); //Recurseifwehaveacause ThrowableourCause=getCause(); if(ourCause!=null) ourCause.printStackTraceAsCause(s,trace); } /** *填充异常轨迹 */ publicsynchronizednativeThrowablefillInStackTrace(); /** *返回当前的异常轨迹的拷贝 */ publicStackTraceElement[]getStackTrace(){ return(StackTraceElement[])getOurStackTrace().clone(); } /** *获取当前的异常轨迹 */ privatesynchronizedStackTraceElement[]getOurStackTrace(){ //如果第一次调用此方法则初始化异常轨迹数组 if(stackTrace==null){ //获得异常轨迹深度 intdepth=getStackTraceDepth(); //创建新的异常轨迹数组,并填充它 stackTrace=newStackTraceElement[depth]; for(inti=0;i<depth;i++) stackTrace[i]=getStackTraceElement(i);//获取指定位标的异常轨迹 } returnstackTrace; } /** *设置异常轨迹 */ publicvoidsetStackTrace(StackTraceElement[]stackTrace){ //拷贝设置参数 StackTraceElement[]defensiveCopy= (StackTraceElement[])stackTrace.clone(); //如果设置参数有空元素则抛出异常 for(inti=0;i<defensiveCopy.length;i++) if(defensiveCopy[i]==null) thrownewNullPointerException("stackTrace["+i+"]"); //设置当前对象的异常轨迹 this.stackTrace=defensiveCopy; } /** *异常轨迹的深度,0表示无法获得 */ privatenativeintgetStackTraceDepth(); /** *获取指定位标的异常轨迹 */ privatenativeStackTraceElementgetStackTraceElement(intindex); privatesynchronizedvoidwriteObject(java.io.ObjectOutputStreams) throwsIOException { getOurStackTrace(); s.defaultWriteObject(); } }