Rethrowing exceptions in Java without losing the stack trace
Asked Answered
T

9

509

In C#, I can use the throw; statement to rethrow an exception while preserving the stack trace:

try
{
   ...
}
catch (Exception e)
{
   if (e is FooException)
     throw;
}

Is there something like this in Java (that doesn't lose the original stack trace)?

Twitch answered 8/7, 2009 at 11:40 Comment(5)
Why do you think it looses the original stacktrace? The only way to loose it when you throw new SomeOtherException and forget to assign the root cause in the constructor or in initCause().Tranquilize
I believe this is how the code behaves in .Net, but I'm no longer positive. It might be worthwhile to either look it up somewhere or run a small test.Twitch
Throwables don't get modified by throwing them. To update the stack trace you have to call fillInStackTrace(). Conveniently this method gets called in the constructor of a Throwable.Outdo
In C#, yes, throw e; will lose the stacktrace. But not in Java.Maren
Some doc from Oracle about exceptions with Java 7 : Catching Multiple Exception Types and Rethrowing Exceptions with Improved Type CheckingRanchman
A
683
catch (WhateverException e) {
    throw e;
}

will simply rethrow the exception you've caught (obviously the surrounding method has to permit this via its signature etc.). The exception will maintain the original stack trace.

Alfalfa answered 8/7, 2009 at 11:43 Comment(10)
Hi, InterruptedException e gives an unhandled Exception message when I add the throw e line. Not so if I replace it with the broader Exception e. How should this be done properly?Knopp
@James, I just observed that the message goes away if adding "throws XxxException" in function declaration.Crown
In Java 7 compiler for such rethrow is more inteligent. Now it works fine with specific "throws" exceptions in containing method.Corium
@James If you catch(Exception e) { throw e; } that will be unhandled. If you catch(InterruptedException ie) { throw ie; } it will be handled. As a rule of thumb, don't catch(Exception e) - this isn't pokemon, and we don't want to catch 'em all!Binion
I see some code like this in a java project I'm working on - is it a no-op and safe to delete?Zephaniah
@JonnyLeeds If that is a try-with-resources statement, you should not delete it.Teneshatenesmus
@Binion It's not necessarily true that you don't want to "Catch 'em all", it's just a different use case. If you have a top-level loop or event handler (for instance, inside a thread's run) if you don't catch at least RuntimeException and log it, you will often miss the exception altogether AND silently break out of an important loop for what is often a one-time failure. It's also really good for plugin functionality where you don't know what additional code might do or throw... For top-down uses like these catching Exception is often not only a good idea but a best practice.Ultrasonics
@BillK Um, sure. But that top level loop will really be handled by a high level framework, usually. Your typical developer will rarely be writing at that kind of level and if they are, they know when rules of thumbs need to be ignored.Binion
@CorsiKa I mentioned it because the app I work on had a few threads that were randomly eating exceptions. Any thread you don't want to break out of silently should have a catch Exception at the top, and you might want to consider that there are a lot of developers who aren't in your exact situation--many programmers work with threads, not all use frameworks to abstract them--and some write their own frameworks.Ultrasonics
I think it's worth mentioning that it may not be "obvious" to someone learning Java that the surrounding method must permit re-throwing the exception. surroundingMethod() throws WhateverException { ... }Arango
D
91

You can also wrap the exception in another one AND keep the original stack trace by passing in the Exception as a Throwable as the cause parameter:

try
{
   ...
}
catch (Exception e)
{
     throw new YourOwnException(e);
}
Duodenal answered 8/7, 2009 at 11:51 Comment(4)
I would also advise on adding a message alongside, using throw new YourOwnException("Error while trying to ....", e);Swarm
this is what I was looking for, especially the version from the first comment where you can pass your own messageHeyduck
This show the error message correctly but the stack trace shows the error line as line with 'throw new.......(e)' not the original line that caused exception.Courson
This only works if YourOwnException is properly set up, see the 4 public constructors on RuntimeException which call super.Circumspection
C
88

I would prefer:

try
{
    ...
}
catch (FooException fe){
   throw fe;
}
catch (Exception e)
{
    // Note: don't catch all exceptions like this unless you know what you
    // are doing.
    ...
}
Checked answered 8/7, 2009 at 11:44 Comment(7)
Definitely proper in Java to catch specific exceptions than generic and checking for instance of. +1Beater
And lets hope FooException is unchecked or is declared in the enclosing method's throws part. C# exceptions are unchecked and can be re-thrown freelyTranquilize
-1 because you should never catch plain "Exception" unless you know what you're doing.Rozier
@Stroboskop: true, but to answer it's best to use the same (similar) code as in the question!Ambrose
In this case, yes. However, sometimes, you can recover from a custom exception only if the attributes of the (custom) exception have some "recoverable" values, hence the interest of the above form.Undesigning
Sometimes catching all exceptions is ok. Such as when you are writing a test case. Or for logging purposes. Or in the main where not catching means crashing.Sorn
@JohnHenckel and others: Valid points inded. I updated the question to make it clear that catching Exception is typically not the right thing to do, in most (but not all) cases.Hurling
E
21

In Java is almost the same:

try
{
   ...
}
catch (Exception e)
{
   if (e instanceof FooException)
     throw e;
}
Erechtheum answered 8/7, 2009 at 11:42 Comment(5)
I would add a specific catch for FooExceptionDawdle
In this specific case I agree, but adding a specific catch may not be the right choice - imagine you have some common code for all exceptions and after, for a particular exception, rethrow it.Erechtheum
@MarkusLausberg But finally doesn't catch exceptions.Outdo
Yes, but this was not the question.Checked
As you mention in the comment, this code would only make sense if you have more code that uses e after the if. Otherwise, it's just not quite right to use instanceof. You could add an ellipsis or comment stating that.Splashboard
C
15

In Java, you just throw the exception you caught, so throw e rather than just throw. Java maintains the stack trace.

Calcaneus answered 8/7, 2009 at 11:43 Comment(0)
T
7

Stack trace is prserved if you wrap the catched excetion into an other exception (to provide more info) or if you just rethrow the catched excetion.

try{ ... }catch (FooException e){ throw new BarException("Some usefull info", e); }

Thanatos answered 28/12, 2017 at 9:48 Comment(0)
S
6

something like this

try 
{
  ...
}
catch (FooException e) 
{
  throw e;
}
catch (Exception e)
{
  ...
}
Skatole answered 8/7, 2009 at 11:47 Comment(0)
W
5
public int read(byte[] a) throws IOException {
    try {
        return in.read(a);
    } catch (final Throwable t) {
        /* can do something here, like  in=null;  */
        throw t;
    }
}

This is a concrete example where the method throws an IOException. The final means t can only hold an exception thrown from the try block. Additional reading material can be found here and here.

Whittle answered 7/1, 2015 at 19:34 Comment(1)
S
3

I was just having a similar situation in which my code potentially throws a number of different exceptions that I just wanted to rethrow. The solution described above was not working for me, because Eclipse told me that throw e; leads to an unhandeled exception, so I just did this:

try
{
...
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {                    
    throw new RuntimeException(e.getClass().getName() + ": " + e.getMessage() + "\n" + e.getStackTrace().toString());
}

Worked for me....:)

Scincoid answered 20/11, 2019 at 10:54 Comment(2)
Avoid self-made extraction of info about e. Better pack the original exception with throw new RuntimeException("Some usefull info", e). In the string, gives somes usefull info that are missing in e, for example some important arguments of your method, info about the context, or whatever will help debugging.Overjoy
Please don't do this : 1. You are packing checked exception in RuntimeExceptions. 2. You are loosing informationsEclair

© 2022 - 2024 — McMap. All rights reserved.