JAVA 篇之异常

本文详细介绍了Java中的异常处理机制,包括异常类的结构、异常栈信息的打印过程以及异常的具体实现方式。通过示例展示了FileNotFoundException的抛出和捕获过程,并深入分析了Throwable类中涉及的本地方法。
摘要由CSDN通过智能技术生成

1、结构

224711_nii1_2663859.png

最顶层的类是序列化类,作用,异常堆栈信息可以通过网络流传送,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;

看到没有这个是入栈的操作(知识:每个方法都代码一个栈帧),出栈的顺序和入栈顺序是相反的(所以说栈是先进后出的)。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

转载于:https://my.oschina.net/chenping12/blog/1476711

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值