33
votes

Considering you have code like this:

doSomething() // this method may throw a checked a exception
//do some assignements calculations
doAnotherThing() //this method may also throw the same type of checked exception
//more calls to methods and calculations, all throwing the same kind of exceptions.

Now I know, there is in fact a performance hit when constructing the exception, specifically unwinding the stack. And I have also read several articles pointing to a slight performance hit when entering try/catch blocks, but none of the articles seem to conclude anything.

My question is, is it recommended to keep the lines inside the try catch to bare minimum?, i.e. ONLY have inside the try clause the lines that can actually throw the exception you are catching. Does the code inside the try clause run slower or cause any performance hit?.

But more important what it is the best practice/more readable solution considering doing this:

try {
    doSomething() // this method may throw a checked a exception
//do some assignements calculations
doAnotherThing() //this method may also throw the same type of checked exception
//more calls to methods and calculations, all throwing the same kind of exceptions.
}
catch (MyCheckedException e) {
   //handle it
}

or :

try {
    doSomething() // this method may throw a checked a exception
}
catch (MyCheckedException e) {
   //Store my exception in a Map (this is all running in a loop and I want it to   continue running, but I also want to know which loops didn't complete and why)
   continue;     
} 
 //do some assignements calculations
try {
    doAnotherThing() // this method may throw a checked a exception
}
catch (MyCheckedException e) {
    //Store my exception in a Map (this is all running in a loop and I want it to   continue running, but I also want to know which loops didn't complete and why)
   continue;
} 

This is considering that you will handle ALL this checked exceptions exactly the same way of course.

9
These two examples are not equivalent: Consider the first example where doSomething() throws an exception. The assignments/calculations that follow will never execute. In the second example, they will execute because the exception thrown by doSomething() is handled before the assignments/calculations. Consider if it makes sense to execute the assignments/calculations if doSomething() throws an exception. Will the results of the calculations still be correct?FrustratedWithFormsDesigner
@FrustratedWithFormsDesigned: agreed, see my answer. However, "handle it" might contain a throw; statement or something. The content is left as an exercise to the reader, I guess!André Caron
You are correct, I modified my example, to reflect the question. It would only make sense to continue executing the method if doSomething() completes correctly in my case.Oscar Gomez

9 Answers

17
votes

In your example here, the real performance hit is if both doSomething() and doAnotherThing() both throw exceptions. Entering a try-block is fast, until it throws an exception.

It really comes down to what your situation is. If you need to do the same thing when MyCheckedException is thrown either way, I'd consider it both more readable and more performant to have them both in the same try block, but if you need to handle the two different situations differently then of course it makes more sense to separate them.

Edit: I read the end of your comment, you're assuming handling both the same way, in which case I'd put them both in the same try-block.

24
votes

Is it recommended to keep the lines inside the try catch to bare minimum?

No. Can't imagine how you could think that the length of a try block or indeed of any block can have any impact on performance.

Does the code inside the try clause run slower or cause any performance hit?.

No.

As you observed, exceptions only incur performance costs when thrown.

If you're concerned about 'try' performance, surely the thing to do is keep the code inside to a maximum?

4
votes

I'm not sure which one is slower, but don't forget that a try block is control flow. You should make the control flow match what you're trying to accomplish. For me, the choice between

try {
    // op 1.
    // op 2.
    / ...
    // op n.
}
catch ( MyCheckedException error )
{
    // handle any `MyException` in op 1, 2 ... n.
}

and sepearate catch blocks for each is mainly a decision of whether I want to do different handling for each op, keep executing until op n regardless of errors or try to execute all of them and fail at the first error.

Write clean, readable code, and then search for bottlenecks. If existing experiments can't conclude to basic guidelines, then I suspect that's not where you'll find your bottlenecks anyways.

3
votes

Having try-blocks should have basically zero performance effect in any decent JVM. The real hit comes when an exception is actually thrown.

You can read this article to get an idea of how the JVM implements exception handling in bytecode: it creates "exception tables" that map regions of code to catch/finally blocks, so:

  • Bytecode for a try-block is the same as for a standard { } block
  • The only extra cost in the non-throwing case is that of having the "exception table" loaded in memory.

Of course, when an exception is thrown there is a lot of stack work going on, so it is going to have a cost. Anyway, it is not nearly as bad as with SEH (.NET exceptions).

2
votes

Your code should only handle the exceptions it can do something about, the others should be re-thrown.

The amount of code in the try block does not cause slowdowns, hitting the catch block does. But unless you are trying to write real high performance code, I would not worry about it.

1
votes

Keeping the number of try/catch blocks to a minimum will improve performance slightly, but moving the work around won't really make a difference, except for work that would be skipped because of a thrown exception.

0
votes

Exceptions cost a lot because each time an exception is thrown, the stack trace must be created and populated.

Imagine a balance transfer operation which fails in 1% of cases due to lack of funds. Even with this relatively little rate of failures, performance may be severely impacted.

See source code and benchmark results here.

0
votes

I'm not sure that inside the try block the performance might be slow, but what I do know is that the performance of ex.getStackTrace() is very slow because it reveals all of your command stack and you should be careful with that.

-1
votes

There is overhead for each exception block. So, you want to maximize the amount of time you stay in a block.

However, you also have to consider the difference in semantics. In your first example, if doSomething() throws an exception, then doAnotherThing() won't be run. In the second example (assuming the catch handler doesn't return), doAnotherThing() WILL be run.