`try/catch`如何在细节上工作

Jak*_* M. 9 java stack exception-handling exception

我想了解try {} catch {}块和堆栈跟踪如何工作的内部结构.

我正在阅读这篇关于异常处理反模式的伟大文章,并发现以下段落:

catch (NoSuchMethodException e) {
  throw new MyServiceException("Blah: " +
      e.getMessage());
}
Run Code Online (Sandbox Code Playgroud)

这会破坏原始异常的堆栈跟踪,并且总是错误的.

从那以后,我意识到,我并不真的知道如何try/catch工作的.我的理解如下.考虑这个例子:

void top() {
    try {
        f();
    } catch (MyException ex) {
        handleIt(); 
    } finally {
        cleanup();
    }
}

void f() {
    g();
}

void g() {
    throw new MyException();
}
Run Code Online (Sandbox Code Playgroud)

当我调用时top(),调用链 在调用堆栈上top -> f -> g 留下两个堆栈帧(for topffunctions).当引发异常时g,程序会冒出执行堆栈,直到找到try/catch处理异常的块.同时,它释放堆栈帧并将堆栈跟踪信息附加到可以传递到的一些"魔术"对象,catch并且可以打印堆栈跟踪.

怎么知道被调用的函数被try/catch块"包围"了?此信息是否绑定到堆栈帧?比如,指向错误处理块的指针(某些开关选择匹配catch块)和指向finally块的指针?为什么e.getMessage()在上面的例子中是破坏性的(见评论)?

请注意,我知道如何使用try/catch语句和例外情况,我想知道它是如何工作的内部.

Ale*_*dov 9

"它如何知道被调用的函数被try/catch块"包围"了?"

每个方法的代码都包含Exception Table,它描述了该方法的所有try-catch块.

当调用过程(函数,方法)时,当前堆栈帧附加有调用指令的地址,以便在正确的指令(调用指令之后的下一个)恢复该帧的执行.

执行throw语句时,JVM 会检查每个堆栈帧 以确定该帧是否可以处理异常.它可以包含一个包含调用指令的try-catch块,并且块的异常类型是抛出异常的超类型(或相同).如果找到这样的帧,则帧从指向try-catch块的指令恢复其执行.