Java “try/catch”在细节上是如何工作的
我想了解Java “try/catch”在细节上是如何工作的,java,exception,exception-handling,stack,Java,Exception,Exception Handling,Stack,我想了解try{}catch{}块和堆栈跟踪是如何工作的 我在阅读时发现以下段落: 这会破坏原始异常的堆栈跟踪,并且总是错误的 在那之后,我意识到我真的不知道try/catch是如何工作的。我的理解如下。考虑这个例子: void top() { try { f(); } catch (MyException ex) { handleIt(); } finally { cleanup(); } } void f()
try{}catch{}
块和堆栈跟踪是如何工作的
我在阅读时发现以下段落:
这会破坏原始异常的堆栈跟踪,并且总是错误的
在那之后,我意识到我真的不知道try/catch
是如何工作的。我的理解如下。考虑这个例子:
void top() {
try {
f();
} catch (MyException ex) {
handleIt();
} finally {
cleanup();
}
}
void f() {
g();
}
void g() {
throw new MyException();
}
当我调用top()
时,调用链top->f->g
在调用堆栈上留下两个(用于top
和f
函数)。在g
中引发异常时,
程序将执行堆栈冒泡,直到找到处理异常的try/catch
块。同时,它释放堆栈帧并将堆栈跟踪信息附加到一些“神奇”对象,这些对象可以传递到catch
,并且可以打印堆栈跟踪
它如何知道被调用的函数被try/catch块“包围”了?此信息是否绑定到堆栈帧?比如,指向错误处理块的指针(一些开关选择匹配的
catch
块),以及指向finally
块的指针?为什么e.getMessage()
在上述示例中具有破坏性(请参见注释)
注意,我知道如何使用try/catch和exceptions,我想知道它在内部是如何工作的。当抛出异常时,完整的调用堆栈信息不是附加到某个魔法对象,而是附加到创建的exception对象。当异常“冒泡”时不会发生这种情况-它在创建时发生,并且总是包含完整的调用链 被调用函数不需要知道它被try-catch块包围,它只创建一个包含调用链的异常对象,并将其传递给调用方法。这个方法必须决定它是处理异常,因为它被某个catch子句捕获,还是进一步传递它。在到达调用链的顶端并且VM处理它们之前,不会捕获的异常会冒泡——通常是通过打印堆栈跟踪并终止 关于
e.getMessage
-示例:
完整堆栈信息仅包含在原始异常中。在放弃原始异常对象e的给定示例中,仅将包含的消息传递给新创建的异常对象。这个异常只“知道”它自己的调用堆栈,所以附加到e的原始信息丢失了。低级方法只是抛出异常,我们应该在高级处理它们。考虑一下你的例子。应该是这样的
void top() {
try {
f();
} catch (MyException ex) {
handleIt();
} finally {
cleanup();
}
}
void f() throws MyException {
try{
g();
}catch(MyException e){
throws new MyException("Error in g()",e);
}
}
void g() throws MyException{
throw new MyException();
}
它如何知道被调用函数被try/catch块“包围”
每个方法的代码都包含描述该方法的所有try-catch块的代码
调用过程(函数、方法)时,当前堆栈帧将附加调用指令的地址,以便在正确的指令(调用指令后的下一个指令)恢复该帧的执行
当执行throw语句时,JVM将检查该帧是否可以处理异常。如果它的方法包含一个包含调用指令的try-catch块,并且该块的异常类型是抛出异常的超类型(或与抛出异常的超类型相同),则它可以。如果找到这样的帧,该帧将从try-catch块指向的指令恢复其执行。异常将从最初抛出它的方法向上传播到调用堆栈,直到调用堆栈中的方法捕获它。如果方法a调用B,B调用C,则调用堆栈如下所示:
A
B
C
当方法C返回时,调用堆栈仅包含A和B。
异常从最初抛出它的方法向上传播到调用堆栈,直到调用堆栈中的方法捕获它
当抛出异常时,该方法在“throw”语句之后立即停止执行。“throw”语句之后的任何语句都不会执行。当异常被“catch”块捕获时,程序将恢复执行 如果一个方法调用另一个抛出已检查异常的方法,则调用方法将被强制传递异常或捕获异常。捕获异常是使用try-catch块完成的。如果try块内调用的任何方法或执行的任何语句均未引发异常,则将忽略catch块。如果在try块内引发异常,例如来自divide方法的异常,则调用方法callDivide的程序流,被中断,就像程序流在divide中一样。程序流在调用堆栈中的catch块处恢复,该块可以捕获抛出的异常 如果在catch块内抛出异常而未捕获该异常,则catch块将中断,就像try块一样
Hm,你说得对,我没有注意到抛出的问题,但其余的问题仍然有效
A
B
C