How `try / catch` works

I would like to know how try {} catch {} traces of blocks and stacks work.

I read this wonderful article on exception handling antiviruses and found the following paragraph:

 catch (NoSuchMethodException e) { throw new MyServiceException("Blah: " + e.getMessage()); } 

This destroys the stack trace of the original exception and is always incorrect.

After that, I realized that I really don't know how try/catch works. My understanding is as follows. Consider an example:

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

When I call top() , the chain of calls top -> f -> g leaves two stack frames in the call stack (for the top and f functions). When the exception is expressed in g , the program bubbles up the execution stack until it finds a try/catch that handles the exception. In the meantime, it frees up the stack frames and attaches the stack trace information to some β€œmagic” object that can be passed to catch , and the stack trace can be printed.

How does he know that the called function is "surrounded" by the try / catch block? Is this information related to the stack frame? For example, a pointer to an error processing block (some switches select the corresponding catch ) and a pointer to a finally block? Why is e.getMessage() destructive in the above example (see comments)?

Notice, I know how to use try / catch and exceptions, I want to know how it works inside.

+6
source share
3 answers

"How does he know that the called function is" surrounded "by the try / catch block?"

Each method code contains an exception table that describes all the try-catch blocks of this method.

When a procedure (function, method) is called, the current stack stack is added with the address of the calling command to restore the execution of this frame in the correct command (the next after the call command).

When the throw statement is executed, the JVM checks each frame in the stack to see if that frame can handle the exception. This can be if its method contains a try-catch block that contains the calling command, and the block exception type is a supertype (or the same one) as in the case of an exception. If such a frame is found, the frame restores execution from the instruction specified in the try-catch block.

+6
source

When an exception is thrown, full information about the call stack is not tied to any magic objects, but to the exception object being created. This does not happen until the exception is "bubbling" - it occurs when it is created, and it always contains a complete chain of calls.

The called function does not need to know that it is surrounded by a try-catch block, it simply creates an Exception object that contains a chain of calls and passes it to the calling method. This method should decide whether it can handle the exception because it is caught by some catch clause or if it passes it on. An exception that does not fall into the bubble until they reach the top of the calling chain and the virtual machine processes them β€” usually by printing the stack trace and terminating.

Regarding e.getMessage -example: Full stack information is contained only in the original exception. In this example, that the original exception object e is discarded, the message just sent is passed to the newly created Exception object. And this exception only "knows" its own call stack, so the original information attached to e is lost.

+3
source

The lower level method simply throws an exception, and we need to handle them at the upper level. Consider your example. It should like

 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(); } 
0
source

Source: https://habr.com/ru/post/957327/


All Articles