Karim
Karim

Reputation: 6283

The difference between try/catch/throw and try/catch(e)/throw e

What is the difference between

try { }
catch
{ throw; }

and

try { }
catch(Exception e)
{ throw e;}

?

And when should I use one or the other?

Upvotes: 106

Views: 82580

Answers (4)

Bruno Reis
Bruno Reis

Reputation: 37832

The constructions

try { ... }
catch () { ... } /* You can even omit the () here */

try { ... }
catch (Exception e) { ... }

are similar in that both will catch every exception thrown inside the try block (and, unless you are simply using this to log the exceptions, should be avoided). Now look at these:

try { ... }
catch ()
{
    /* ... */
    throw;
}

try { ... }
catch (Exception e)
{
    /* ... */
    throw;
}

try { ... }
catch (Exception e)
{
    /* ... */
    throw e;
}

The first and second try-catch blocks are EXACTLY the same thing, they simply rethrow the current exception, and that exception will keep its "source" and the stack trace.

The third try-catch block is different. When it throws the exception, it will change the source and the stack trace, so that it will appear that the exception has been thrown from this method, from that very line throw e on the method containing that try-catch block.

Which one should you use? It really depends on each case.

Let's say you have a Person class with a .Save() method that will persist it into a database. Let's say that your application executes the Person.Save() method somewhere. If your DB refuses to save the Person, then .Save() will throw an exception. Should you use throw or throw e in this case? Well, it depends.

What I prefer is doing:

try {
    /* ... */
    person.Save();
}
catch(DBException e) {
    throw new InvalidPersonException(
       "The person has an invalid state and could not be saved!",
       e);
}

This should put the DBException as the "Inner Exception" of the newer exception being throw. So when you inspect this InvalidPersonException, the stack trace will contain info back to the Save method (that might be sufficient for you to solve the problem), but you still have access to the original exception if you need it.

As a final remark, when you are expecting an exception, you should really catch that one specific exception, and not a general Exception, ie, if you are expecting an InvalidPersonException you should prefer:

try { ... }
catch (InvalidPersonException e) { ... }

to

try { ... }
catch (Exception e) { ... }

Upvotes: 154

Darin Dimitrov
Darin Dimitrov

Reputation: 1039588

The first preserves the stack trace while the second resets it. This means that if you use the second approach the stack trace of the exception will always start from this method and you will lose the original exception trace which could be disastrous for someone reading exception logs as he will never find out the original cause of the exception.

The second approach might be useful when you want to add additional information to the stack trace but it is used like this:

try
{
    // do something
}
catch (Exception ex)
{
    throw new Exception("Additional information...", ex);
}

There's a blog post discussing the differences.

Upvotes: 35

Guffa
Guffa

Reputation: 700910

The difference between a parameterless catch and a catch(Exception e) is that you get a reference to the exception. From framework version 2 unmanaged exceptions are wrapped in a managed exception, so the parameterless exception is no longer useful for anything.

The difference between throw; and throw e; is that the first one is used to rethrow exceptions and the second one is used to throw a newly created exception. If you use the second one to rethrow an exception, it will treat it like a new exception and replace all stack information from where it was originally thrown.

So, you shold not use either of the alternatives in the question. You should not use the parameterless catch, and you should use throw; to rethrow an exception.

Also, in most cases you should use a more specific exception class than the base class for all exceptions. You should only catch the exceptions that you anticipate.

try {
   ...
} catch (IOException e) {
   ...
   throw;
}

If you want to add any information when rethrowing the exception, you create a new exception with the original exception as an inner exception to preservere all information:

try {
   ...
} catch (IOException e) {
   ...
   throw new ApplicationException("Some informative error message", e);
}

Upvotes: 5

Otávio Décio
Otávio Décio

Reputation: 74320

You should use

try { }
catch(Exception e)
{ throw }

if you want to do something with the exception before re-throwing it (logging for example). The lonely throw preserves stack trace.

Upvotes: 6

Related Questions