解析Java中所有错误和异常的父类java.lang.Throwable_java

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

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
, 异常
, 错误
java.lang.Throwable
java所有异常的父类、java异常类的父类、所有异常的父类、所有异常的父类是、异常的父类,以便于您获取更多的相关知识。

时间: 2024-09-24 11:30:10

解析Java中所有错误和异常的父类java.lang.Throwable_java的相关文章

消灭bug秘籍 如何处理大型软件中的错误和异常

[51CTO.com快译] "我在测试中没有发现任何bug,这就意味着没有bug--对吗?"千万不要这样认为.由于大型软件的复杂程度很高,不管你做了多少测试,都不可能达到零bug的程度.因为你并不能揣测出用户的所有使用方式,因此,了解应用程序中错误和异常之间的差异,是非常重要的.为此,你要选择正确的方式来处理这些错误和异常,以积极的态度来确保应用的正常运行,对你的开发团队和最终用户负责. 测试的本身亦是个问题 即便你的测试是最彻底的,你依然只是在测试特定的情况,而且自己的偏好也在测试过

静态 非静态 覆盖-java中子类的静态方法能否覆盖父类的静态方法?请大神们帮忙分析下!

问题描述 java中子类的静态方法能否覆盖父类的静态方法?请大神们帮忙分析下! 第一题: class Parent { public void nonStaticMethod() { System.out.println("Parent's Non-Static Method is Called"); } public static void staticMethod() { System.out.println("parent's static method is call

java中 包里存放的是类名.java 还是类名.class?

问题描述 java中 包里存放的是类名.java 还是类名.class? 问题1 java中 包里存放的是类名.java 还是类名.class? 类名.java文件一定要放在所 属包目录下吗? 问题2.见下代码 package packb; public class DemoB { public static void main(String[] args) { System.out.println("Hello World!"); } } package packa; class D

Java中关于Null的9个解释(Java Null详解)_java

对于Java程序员来说,null是令人头痛的东西.时常会受到空指针异常(NPE)的骚扰.连Java的发明者都承认这是他的一项巨大失误.Java为什么要保留null呢?null出现有一段时间了,并且我认为Java发明者知道null与它解决的问题相比带来了更多的麻烦,但是null仍然陪伴着Java. 我越发感到惊奇,因为java的设计原理是为了简化事情,那就是为什么没有浪费时间在指针.操作符重载.多继承实现的原因,null却与此正好相反.好吧,我真的不知道这个问题的答案,我知道的是不管null被Ja

学习Java中的日期和时间处理及Java日历小程序的编写_java

Java 在 java.util 包中提供了 Date 类,这个类封装了当前的日期和时间. Date 类支持两种构造函数.第一个构造函数初始化对象的当前日期和时间. Date( )下面的构造函数接收一个参数等于自1970年1月1日午夜起已经过的毫秒数 Date(long millisec) 一旦有一个可用的日期对象,可以调用以下任何一种支持的方法使用时间: SN 方法和描述 1 boolean after(Date date) 如果调用Date对象包含或晚于指定的日期则返回true,否则,返回f

java中的错误看不出来

问题描述 //将当前的时间转换成"yyyy-MM-ddHH:mm:ss"格式并且打印今天是几号(使用String的subSting()方法)/*//第一步获取当前日期Datedate=newDate();//格式化标准Strings1="yyyy-MM-ddHH:mm:ss";SimpleDateFormatsdf=newSimpleDateFormat(s1);Strings2=sdf.format(date);Strings3=s2.subString(8.10

深入探讨Java中的异常与错误处理

Java中的异常处理机制已经比较成熟,我们的Java程序到处充满了异常的可能,如果对这些异常不做预先的处理,那么将来程序崩溃就无从调试,很难找到异常所在的位置.本文将探讨一下Java中异常与错误的处理方法,一起来看看. 异常与错误: 异常: 在Java中程序的错误主要是语法错误和语义错误,一个程序在编译和运行时出现的错误我们统一称之为异常,它是VM(虚拟机)通知你的一种方式,通过这种方式,VM让你知道,你(开发人员)已经犯了个错误,现在有一个机会来修改它.Java中使用异常类来表示异常,不同的异

Java中异常机制的深入研究

由于本文旨在探讨Java"异常机制"的深层原理,因此关于"异常"的使用方法都不做详细说明.首先看一段非常熟悉的用于打开一个文件的C程序段: FILE *fp;fp=fopen(filename,"rw");if(fp==NULL){ printf("cannot open file\n"); exit(0);} 在这段程序中,if条件语句中的一段用来处理没有找到指定文件,或者其它原因无法正确打开指定文件.可是如果遇到一个责任心

Java中利用Either和Option进行函数式错误处理

在本期 函数式思维 的文章中,将探讨在以函数方式显示 Java 错误的同时仍保留类型安全的方法,说明如何通过函数式返回来包装经过检查的异常,并介绍一个方便的抽象,其名称为 Either. 当您研究函数式编程等深奥学科时,令人着迷的分支偶尔会出现.在 函数式思维:函数设计模式,第 3 部分 中,我在迷你系列中继续以函数的方式重新思考传统的 Gang of Four 设计模式.在下一期文章中,我将回到这一主题,讨论 http://www.aliyun.com/zixun/aggregation/16