服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服务器之家 - 编程语言 - JAVA教程 - 解析Java中所有错误和异常的父类java.lang.Throwable

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

2020-04-09 15:11Riddick JAVA教程

这篇文章主要介绍了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语句的支持,可在任何时候将返回方法,如下面的方法定义:

?
1
2
3
public String myMethod() {
throw new MyError();
}

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

?
1
2
3
public String myMethod() {
throw new MyException();
}

正确的方法定义如下:

?
1
2
3
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源代码解析

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
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();
  }
}

 

延伸 · 阅读

精彩推荐