I am not familiar with error/exception handling.
What is happening "under the hood" when an exception is caught
and thrown
?
I.e. what is the point of catching an exception in a try-catch block, then throwing it?
E.g:
try {
//Stuff
} catch(StuffException e) {
throw new MyException();
}
}
Q #3) What happens when a catch block throws an exception? Answer: When an exception is thrown in the catch block, then the program will stop the execution. In case the program has to continue, then there has to be a separate try-catch block to handle the exception raised in the catch block.
When an exception is thrown using the throw keyword, the flow of execution of the program is stopped and the control is transferred to the nearest enclosing try-catch block that matches the type of exception thrown. If no such match is found, the default exception handler terminates the program.
If an exception is thrown inside the catch-block and that exception is not caught, the catch-block is interrupted just like the try-block would have been. When the catch block is finished the program continues with any statements following the catch block. In the example above the "System.
- The main method should simply terminate if any exception occurs. The throws clause only states that the method throws a checked FileNotFoundException and the calling method should catch or rethrow it. If a non-checked exception is thrown (and not catch) in the main method, it will also terminate.
Regarding the inner workings of the exception mechanism: There is plenty of documentation on this. I'm particularly a fan of this article: http://www.javaworld.com/article/2076868/learn-java/how-the-java-virtual-machine-handles-exceptions.html
Ultra-short summary: When an exception is thrown, the jvm looks up in a table where the execution (of the init() method of the exception) continues.
For the second part of your question:
what is the point of catching an exception in a try-catch block, then throwing it?
I see some reasons for catching an exception an throwing another one:
You might want to catch an unchecked exception (because you know, "something bad might happen") and throw a checked one - so the caller has to handle it.
You want to use a custom Exception, maybe with additional information/logic
You're Implementing an error facade, e.g. throwing exceptions and catching them at the end in the facade.
Your example catches something with the type of StuffException, then throws a MyException. This is done to abstract away the original exception; it might be that the original exception is an implementation detail that the thing calling it doesn't need to know about (and which needs to be able to change, so that the caller shouldn't depend on it), and the exception thrown to replace it is part of the published API, which the caller can depend on. This is the case with Hibernate, it catches SQLExceptions generated in the course of calling JDBC functions, and wraps them in Hibernate exceptions, so calling code recognizes them as being thrown from Hibernate, and calling code doesn't depend directly on the JDBC exceptions, but on Hibernate's. If JDBC changed what exceptions it throws then, once Hibernate adapted to it, users of Hibernate wouldn't have to change.
What's bad about this example is that the stacktrace information for the original StuffException gets discarded when e goes out of scope, and MyException's stacktrace starts with the location that threw the MyException, making it difficult to find the source of the actual problem. Assigning the old exception to the new exception as its cause would preserve the original stacktrace information:
try {
//Stuff
} catch(StuffException e) {
MyException myException = new MyException();
myException.initCause(e);
throw myException;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With