解析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();
}
}