1、结构
最顶层的类是序列化类,作用,异常堆栈信息可以通过网络流传送,Throwable是顶层的异常类(你可以看到所有的子类的构造函数都是调用父类的构造器,最后到达Throwable),Exception作为Throwable和其他异常的桥梁(这样更好的扩展异常类,比如自定义异常)。
2、异常的栈信息是怎么打印出来的
我们接触最多的就是异常可以帮助我们打印堆栈信息,下面通过一个列子说明
try { InputStream inputStream = new FileInputStream("D://aa"); } catch (FileNotFoundException e) { e.printStackTrace(); }
主要是看printStackTrace()栈的源码
synchronized (s.lock()) { // Print our stack trace s.println(this); StackTraceElement[] trace = getOurStackTrace(); //获取堆栈信息 for (StackTraceElement traceElement : trace) s.println("\tat " + traceElement); // Print suppressed exceptions, if any for (Throwable se : getSuppressed()) se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu); // Print cause, if any Throwable ourCause = getCause(); if (ourCause != null) ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu); }
getOurStackTrace()源码
if (stackTrace == UNASSIGNED_STACK || (stackTrace == null && backtrace != null) /* Out of protocol state */) { int depth = getStackTraceDepth(); //获取栈的深度 stackTrace = new StackTraceElement[depth]; for (int i=0; i < depth; i++) stackTrace[i] = getStackTraceElement(i); //获取栈的信息 } else if (stackTrace == null) { return UNASSIGNED_STACK; }
getStackTraceDepth() 和 getStackTraceElement(i)
native int getStackTraceDepth(); //本地方法
native StackTraceElement getStackTraceElement(int index); //本地方法
上诉方法都是在Throwable,从源码可见,其实栈的信息最后都是通过顶层父类Throwable中的方法打印出来,栈的信息是本地方法获取,最后看下异常信息
java.io.FileNotFoundException: D:\aa (系统找不到指定的文件。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at main.test.Throw.main(Throw.java:30)
如果你仔细看new FileInputStream(String name)构造器的源码的话你会看到执行流程
public FileInputStream(String name) throws FileNotFoundException { this(name != null ? new File(name) : null); }
public FileInputStream(File file) throws FileNotFoundException { String name = (file != null ? file.getPath() : null); SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(name); } if (name == null) { throw new NullPointerException(); } if (file.isInvalid()) { throw new FileNotFoundException("Invalid file path"); } fd = new FileDescriptor(); fd.attach(this); path = name; open(name); //open }
private void open(String name) throws FileNotFoundException { open0(name); }
private native void open0(String name) throws FileNotFoundException;
看到没有这个是入栈的操作(知识:每个方法都代码一个栈帧),出栈的顺序和入栈顺序是相反的(所以说栈是先进后出的)。