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