In Java, stack traces are generated when an exception is constructed, not when it's thrown. Does anyone know what's the reasoning behind this design?
For example, in the following program, we throw an exception in method test1, but we instantiate the exception in another method, and call test1 from main. As a result, test1 never shows up in the stack trace:
class ExceptionNewVsThrow {
private static RuntimeException instantiateException() {
return new RuntimeException("Hello");
}
private static void test1(Exception exception) throws Exception {
throw exception;
}
public static void main(String[] args) throws Exception {
Exception exception = instantiateException();
test1(exception);
}
}
Exception in thread "main" java.lang.RuntimeException: Hello
at FSystem.experimental.exceptions.ExceptionNewVsThrow.instantiateException(ExceptionNewVsThrow.java:18)
at FSystem.experimental.exceptions.ExceptionNewVsThrow.main(ExceptionNewVsThrow.java:26)
See Are stack traces generated when a Java exception is thrown?
CodePudding user response:
This is the Java language specification for the throws statement : https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.18
And it seems that the throws statement simply throws the exception; it doesn’t build the stack trace that goes into it. Based on the methods for setting the exception (class Throwable) it looks like Java is giving the developer the responsibility of building the exception, initializing it’s cause and stack trace, etc. So if this was part of throws, the developer wouldn’t have the same flexibility.
Therefore, the answer to the question is : it is more powerful and flexible to build stack traces as part of Exception construction.
CodePudding user response:
In Java, stack traces are generated when an exception is constructed, not when it's thrown. Does anyone know what's the reasoning behind this design?
I don't think we can give you the full (original) reasoning because the decisions were most likely made back in the days when Java was called Oak (!)
But a couple of advantages are:
- When you rethrow an exception, the original stacktrace is preserved. So for example, you can catch an exception on one thread, pass it to another thread and rethrow it ... with the original stacktrace.
- You can do things in a custom exception's implementation to change the way that the stacktrace is created; e.g. you can suppress it entirely. Or you could potentially "massage" the stacktrace to hide secret internal details from your customers.
- Capturing the stacktrace is expensive. So if the
throw
statement captured it, there wouldn't be any opportunity to save the expense of capturing it. (Admittedly, modern JVMs have another way of dealing with this ... but we are talking about the original design decisions here.)