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

}

}

本文链接:https://my.lmcjl.com/post/12957.html

展开阅读全文

4 评论

留下您的评论.