解析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的使用对象,如:throw new MyError();和throw new MyException();其中,MyError类是java.lang.Error的子类,MyException类是java.lang.Exception的子类。
2)不同点:java.lang.Error自身及其子类不需要try-catch语句的支持,可在任何时候将返回方法,如下面的方法定义:

public String myMethod() {
throw new MyError();
}

其中MyError类是java.lang.Error类的子类。
java.lang.Exception自身及其子类需要try-catch语句的支持,如下的方法定义是错误的:

public String myMethod() {
throw new MyException();
}

正确的方法定义如下:

public String myMethod() throws MyException {
throw new MyException();
}

其中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源代码解析

package java.lang;
import java.io.*;
/**
*
* Throwable是所有Error和Exceptiong的父类
* 注意它有四个构造函数:
* Throwable()
* Throwable(String message)
* Throwable(Throwable cause)
* Throwable(String message, Throwable cause)
*
*/
public class Throwable implements Serializable {
  private static final long serialVersionUID = -3042686055658047285L; 

  /**
  * Native code saves some indication of the stack backtrace in this slot.
  */
  private transient Object backtrace; 

  /**
  * 描述此异常的信息
  */
  private String detailMessage; 

  /**
  * 表示当前异常由那个Throwable引起
  * 如果为null表示此异常不是由其他Throwable引起的
  * 如果此对象与自己相同,表明此异常的起因对象还没有被初始化
  */
  private Throwable cause = this; 

  /**
  * 描述异常轨迹的数组
  */
  private StackTraceElement[] stackTrace; 

  /**
  * 构造函数,起因对象没有被初始化可以在以后使用initCause进行初始化
  * fillInStackTrace可以用来初始化它的异常轨迹的数组
  */
  public Throwable() {
   fillInStackTrace();
  } 

  /**
  * 构造函数
  */
  public Throwable(String message) {
   //填充异常轨迹数组
   fillInStackTrace();
   //初始化异常描述信息
   detailMessage = message;
  } 

  /**
  * 构造函数,cause表示起因对象
  */
  public Throwable(String message, Throwable cause) {
   fillInStackTrace();
   detailMessage = message;
   this.cause = cause;
  } 

  /**
  * 构造函数
  */
  public Throwable(Throwable cause) {
   fillInStackTrace();
   detailMessage = (cause==null ? null : cause.toString());
   this.cause = cause;
  } 

  /**
  * 获取详细信息
  */
  public String getMessage() {
   return detailMessage;
  } 

  /**
  * 获取详细信息
  */
  public String getLocalizedMessage() {
   return getMessage();
  } 

  /**
  * 获取起因对象
  */
  public Throwable getCause() {
   return (cause==this ? null : cause);
  } 

  /**
  * 初始化起因对象,这个方法只能在未被初始化的情况下调用一次
  */
  public synchronized Throwable initCause(Throwable cause) {
   //如果不是未初始化状态则抛出异常
   if (this.cause != this)
    throw new IllegalStateException("Can't overwrite cause"); 

   //要设置的起因对象与自身相等则抛出异常
   if (cause == this)
    throw new IllegalArgumentException("Self-causation not permitted"); 

   //设置起因对象
   this.cause = cause;
   //返回设置的起因的对象
   return this;
  } 

  /**
  * 字符串表示形式
  */
  public String toString() {
   String s = getClass().getName();
   String message = getLocalizedMessage();
   return (message != null) ? (s + ": " + message) : s;
  } 

  /**
  * 打印出错误轨迹
  */
  public void printStackTrace() {
   printStackTrace(System.err);
  } 

  /**
  * 打印出错误轨迹
  */
  public void printStackTrace(PrintStream s) {
   synchronized (s) {
   //调用当前对象的toString方法
    s.println(this);
   //获取异常轨迹数组
    StackTraceElement[] trace = getOurStackTrace(); 

   //打印出每个元素的字符串表示
    for (int i=0; i < trace.length; i++)
    s.println("\tat " + trace[i]); 

   //获取起因对象
    Throwable ourCause = getCause(); 

   //递归的打印出起因对象的信息
    if (ourCause != null)
    ourCause.printStackTraceAsCause(s, trace);
   }
  } 

  /**
  * 打印起因对象的信息
  * @param s 打印的流
  * @param causedTrace 有此对象引起的异常的异常轨迹
  */
  private void printStackTraceAsCause(PrintStream s,
           StackTraceElement[] causedTrace)
  {
   //获得当前的异常轨迹
   StackTraceElement[] trace = getOurStackTrace();
   //m为当前异常轨迹数组的最后一个元素位置,
   //n为当前对象引起的异常的异常轨迹数组的最后一个元素
   int m = trace.length-1, n = causedTrace.length-1;
   //分别从两个数组的后面做循环,如果相等则一直循环,直到不等或数组到头
   while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) {
    m--; n--;
   } 

   //相同的个数
   int framesInCommon = trace.length - 1 - m; 

   //打印出不同的错误轨迹
   s.println("Caused by: " + this);
   for (int i=0; i <= m; i++)
    s.println("\tat " + trace[i]);
   //如果有相同的则打印出相同的个数
   if (framesInCommon != 0)
    s.println("\t... " + framesInCommon + " more"); 

   //获得此对象的起因对象,并递归打印出信息
   Throwable ourCause = getCause();
   if (ourCause != null)
    ourCause.printStackTraceAsCause(s, trace);
  } 

  /**
  * 打印出错误轨迹
  */
  public void printStackTrace(PrintWriter s) {
   synchronized (s) {
    s.println(this);
    StackTraceElement[] trace = getOurStackTrace();
    for (int i=0; i < trace.length; i++)
     s.println("\tat " + trace[i]); 

    Throwable ourCause = getCause();
    if (ourCause != null)
     ourCause.printStackTraceAsCause(s, trace);
   }
  } 

  /**
  * 打印起因对象的信息
  */
  private void printStackTraceAsCause(PrintWriter s,
           StackTraceElement[] causedTrace)
  {
   // assert Thread.holdsLock(s); 

   // Compute number of frames in common between this and caused
   StackTraceElement[] trace = getOurStackTrace();
   int m = trace.length-1, n = causedTrace.length-1;
   while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) {
    m--; n--;
   }
   int framesInCommon = trace.length - 1 - m; 

   s.println("Caused by: " + this);
   for (int i=0; i <= m; i++)
    s.println("\tat " + trace[i]);
   if (framesInCommon != 0)
    s.println("\t... " + framesInCommon + " more"); 

   // Recurse if we have a cause
   Throwable ourCause = getCause();
   if (ourCause != null)
    ourCause.printStackTraceAsCause(s, trace);
  } 

  /**
  * 填充异常轨迹
  */
  public synchronized native Throwable fillInStackTrace(); 

  /**
  * 返回当前的异常轨迹的拷贝
  */
  public StackTraceElement[] getStackTrace() {
   return (StackTraceElement[]) getOurStackTrace().clone();
  } 

  /**
  * 获取当前的异常轨迹
  */
  private synchronized StackTraceElement[] getOurStackTrace() {
   //如果第一次调用此方法则初始化异常轨迹数组
   if (stackTrace == null) {
   //获得异常轨迹深度
    int depth = getStackTraceDepth();
   //创建新的异常轨迹数组,并填充它
    stackTrace = new StackTraceElement[depth]; 

   for (int i=0; i < depth; i++)
    stackTrace[i] = getStackTraceElement(i);//获取指定位标的异常轨迹
   } 

   return stackTrace;
  } 

  /**
  * 设置异常轨迹
  */
  public void setStackTrace(StackTraceElement[] stackTrace) {
   //拷贝设置参数
   StackTraceElement[] defensiveCopy =
    (StackTraceElement[]) stackTrace.clone(); 

   //如果设置参数有空元素则抛出异常
   for (int i = 0; i < defensiveCopy.length; i++)
    if (defensiveCopy[i] == null)
     throw new NullPointerException("stackTrace[" + i + "]"); 

   //设置当前对象的异常轨迹
   this.stackTrace = defensiveCopy;
  } 

  /**
  * 异常轨迹的深度,0表示无法获得
  */
  private native int getStackTraceDepth(); 

  /**
  * 获取指定位标的异常轨迹
  */
  private native StackTraceElement getStackTraceElement(int index); 

  private synchronized void writeObject(java.io.ObjectOutputStream s)
   throws IOException
  {
   getOurStackTrace();
   s.defaultWriteObject();
  }
}
(0)

相关推荐

  • java.lang.AbstractMethodError: org.apache.xerces.dom.DocumentImpl.setXmlVersion问题解决方法

    读取本地的xml文件,通过DOM进行解析,DOM解析的特点就是把整个xml文件装载入内存中,形成一颗DOM树形结构,树结构是方便遍历和和操纵. DOM解析的特性就是读取xml文件转换为 dom树形结构,通过节点进行遍历. 这是W3c关于节点的概念 如果xml中包含有大量的数据,由于dom一次性把xml装入内存中的特性,所以dom不适合于包含大量数据的xml解析.当包含有大量xml的时候,用SAX进行解析比较节省内存. 下面是一个运用DOM进行解析xml文件的例子: xml文件结构如下: <?xm

  • Zend Studio for Eclipse的java.lang.NullPointerException错误的解决方法

    当然这个东西很吃内存,配置差点的就不推荐使用了. 最近用的时候, 发现, 建立PHP工程后,再打开 Zend Studio for Eclipse就出现这个错误 An internal error occurred during: "Building PHP projects ..."java.lang.NullPointerException 很烦人的. 出错后PHP projects 会停止build,代码提示就全部没有了.需要手动rebuild. 今天在zend论坛找到一个解决办

  • Exception in thread main java.lang.NoClassDefFoundError错误解决方法

    错误描述 javac helloworld.java能够通过.但是java helloworld出现错误: hadoop@xuwei-erplab:~/jarfile$ java HelloWorld Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorld (wrong name: org/xuwei/HelloWorld) at java.lang.ClassLoader.defineClass1(N

  • java.lang.OutOfMemoryError 错误整理及解决办法

    java.lang.OutOfMemoryError处理错误 java.lang.OutOfMemoryError异常解决方法 原因: 常见的有以下几种: 1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据: 2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收: 3.代码中存在死循环或循环产生过多重复的对象实体: 4.使用的第三方软件中的BUG: 5.启动参数内存值设定的过小: 常见错误提示: 1.tomcat:java.lang.OutOfMemoryError: Perm

  • 如何解决Mybatis--java.lang.IllegalArgumentException: Result Maps collection already contains value for X

    这两天因为项目需要整合spring.struts2.mybatis三大框架,但启动的时候总出现这个错误,困扰我好久,在网上找到的答案都不是我想要的,今天终于知道原因了. user-mapper.xml如下: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http:/

  • 解决Eclipse add external jars运行出现java.lang.NoClassDefFoundError的方法

    最近发现一个问题,有时候对一个Android项目反复的Add jar和remove jar,发现编译可以通过,但是运行起来当应用到外部jar的对象时,会抛出java.lang.NoClassDefFoundError异常.导致程序奔溃. 查看项目属性,发现java build path里比正常的项目少了Android Dependencies这一项: 通过和丢失之前的项目进行比对,发现差别在于工程根目录下的.classpath文件,<classpathentry exported="tru

  • Android异常 java.lang.IllegalStateException解决方法

    Android异常详情介绍 这种异常我遇到以下两种情况: 1. java.lang.IllegalStateException: No wrapped connection. 2.java.lang.IllegalStateException: Adapter is detached. 原因: 1.单线程一次执行一个请求可以正常执行,如果使用多线程,同时执行多个请求时就会出现连接超时. 2.HttpConnection没有连接池的概念,多少次请求就会建立多少个IO,在访问量巨大的情况下服务器的I

  • 解决出现 java.lang.ExceptionInInitializerError错误问题

    解决出现 java.lang.ExceptionInInitializerError错误问题 今天启动一个项目... 在启动的时候报错... 查了半天错误信息 一直是说hibernate缓存管理出错.. 最后查看启动时候的log 发现在程序中报Java.lang.ExceptionInInitializerError 查看原因 最后是因为自己修改了静态常量是系统启动的时候自动获取properties值 结果获取错误 导致其在代码编译的时候造成出错 错误代码: public static fina

  • c++ mk文件出错Jni调用产生java.lang.UnsatisfiedLinkError错误解决方法

    错误为: Android.mk文件 c++的调用方法为: 复制代码 代码如下: LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := TestNdk LOCAL_CPP_EXTENSION :=com_ndk_test_JniClient.cpp include $(BUILD_SHARED_LIBRARY) c中的调用方法: 复制代码 代码如下: LOCAL_SRC_FILES := com_ndk_test_Jn

  • Java xml出现错误 javax.xml.transform.TransformerException: java.lang.NullPointerException

    Java xml出现错误 javax.xml.transform.TransformerException: java.lang.NullPointerException解决办法: 利用Java操作XML,在操作XML过程中,执行到最后一步,在利用Transformer进行XML转换时出现NullPointerException错误,出问题的部分代码如下: //转换 TransformerFactory tFactory =TransformerFactory.newInstance(); Tr

  • java.lang.Instrument 代理Agent使用详细介绍

    java.lang.Instrument 代理Agent使用 java.lang.Instrument包是在JDK5引入的,程序员通过修改方法的字节码实现动态修改类代码.这通常是在类的main方法调用之前进行预处理的操作,通过java指定该类的代理类来实现.在类的字节码载入JVM前会调用ClassFileTransformer的transform方法,从而实现修改原类方法的功能,实现AOP,这个的好处是不会像动态代理或者CGLIB技术实现AOP那样会产生一个新类,也不需要原类要有接口. (1)

  • java.lang.NoSuchMethodException: com.sun.proxy.$Proxy58.list错误解决办法

    java.lang.NoSuchMethodException: com.sun.proxy.$Proxy58.list错误解决办法 玩web的SSH总会有些令你意想不到的exception,这里其中有很多事自己不小心,或者马虎所造成.因此,解决的方案会各有不同,别人出现的异常解决方案对你的可能无效,就像上面的我报的异常一样,百度了很多很多次,给我的答案无非就是在aop上加上一句,但是非常抱歉,我加上去无效!所以还是那句话,对于自己的异常,还是要自己解决. 首先说明一下,我这次的练习的ssh结构

随机推荐