16

In case of code where you have to do a resource cleanup before exiting a function, is there a major performance difference between these 2 ways of doing it.

  1. Cleaning the resource before every return statement

    void func()
    {
        login();
    
        bool ret = dosomething();
        if(ret == false)
        {
            logout();
            return;
        }
    
        ret = dosomethingelse();
        if(ret == false)
        {
            logout();
            return;
        }
    
        dootherstuff();
    
        logout();
    }
    
  2. Cleaning the resource in a finally block

    void func()
    {
        login();
    
        try
        {
            bool ret = dosomething();
            if(ret == false)
                return;
    
            ret = dosomethingelse();
            if(ret == false)
                return;
    
            dootherstuff();
    
        }
        finally
        {
            logout();
        }
    }
    

I did some basic tests in sample programs and there doesn't seem to be much of a difference. I so much prefer the finally way of doing this - but I was wondering if it will cause any performance hit in a big project.

5
  • 3
    It's not really worth posting as an answer, but no. If you're using Java, which expects exceptions to be the default error handling strategy, then you should use try/catch/finally - the language is optimized for the pattern you are using. Commented Sep 4, 2013 at 13:22
  • 1
    @JonathanRich: how so?
    – haylem
    Commented Sep 4, 2013 at 13:27
  • 2
    Write code cleanly in such a way that it expresses what you're trying to accomplish. Optimize later when you know you have a problem - don't avoid language features because you think that you might shave a few milliseconds off of something that isn't slow in the first place. Commented Sep 4, 2013 at 23:40
  • @mikeTheLiar - If you mean that I should write if(!cond), then it's java which made me do this. In C++, that's how I write code both of booleans and also for other types - i.e. int x; if(!x). Since java allows me to use this only for booleans, I have totally stopped using the if(cond) & if(!cond) in java.
    – user93353
    Commented Sep 7, 2013 at 0:49
  • 1
    @user93353 that makes me sad. I would much rather see (someIntValue != 0) than comparing rather than evaluating booleans. That smells to me, and I refactor it immediately when I see it in the wild. Commented Sep 7, 2013 at 12:23

5 Answers 5

25

As indicated in How slow are Java exceptions? one can see that the slowness of try {} catch {} is within the instatiation of the exception itself.

Creating an exception will fetch the entire call stack from the runtime and this is where the expense is. If you are not creating an exception, this is only very slightly an increase of time.

In the example given in this question there aren't any exceptions, one wouldn't expect any slowdown from creating them - they aren't created. Instead, what is here is a try {} finally {} to handle resource deallocation within the finally block.

So to answer the question, no, there is no real runtime expense within a try {} finally {} structure that doesn't use exceptions (it isn't unheard of, as seen). What is possibly expensive is the maintenance time when one reads the code and sees this not typical code style and the coder has to get their mind around that something else happens in this method after the return before returning to the previous call.


As has been mentioned, maintenance is an argument for both ways of doing this. For the record, after consideration, my preference would be the finally approach.

Consider the maintenance time of teaching someone a new language structure. Seeing try {} finally {} isn't something that one often sees in Java code and thus can be confusing to people. There is a degree of maintenance time for learning a bit more advanced structures in Java than what people are familiar with seeing.

The finally {} block always runs. And this is why you should use it. Consider also the maintenance time of debugging the non-finally approach when someone forgets to include a logout at the proper time, or calls it at the improper time, or forgets to return / exit after calling it so that it is called twice. There are so many possible bugs with this that the use of try {} finally {} makes impossible to have.

When weighing these two costs, it is expensive in maintenance time not to use the try {} finally {} approach. While people can dicker about how many fractional milliseconds or additional jvm instructions the try {} finally {} block is compared to the other version, one must also consider the hours spent in debugging the less than ideal way of addressing resource deallocation.

Write maintainable code first, and preferably in a way that will prevent bugs from being written later.

4
  • 1
    An anon-suggested edit said thus: "try/finally offers guaranties you wouldn't have otherwise regarding runtime exceptions. Whether you like it or not, any line is virtually capable of throwing an exception" - Me: which isn't exactly true. The structure given in the question doesn't have any additional exceptions that would slow down the performance of the code. There are no additional performance impacts by wrapping a try/finally around the block compared to the non-try/finally block.
    – user40980
    Commented Sep 4, 2013 at 15:52
  • 2
    What could be even more expensive in maintenance than understanding this use of try-finally, is having to maintain several clean-up blocks. Now at least you know that if additional clean-up is needed, there is only one place to put it. Commented Sep 4, 2013 at 17:06
  • @BartvanIngenSchenau Indeed. A try-finally is probably the best way to handle it, it just isn't that common of a structure that I've seen in code - people have enough trouble trying to understand try catch finally and exception handling in general.. but try-finaly without a catch? What? People really don't understand it. As you suggested, it is better to understand the language structure than trying to avoid it and do things poorly.
    – user40980
    Commented Sep 5, 2013 at 0:56
  • I mostly wanted to make it known that the alternative to try-finally isn't free either. I wish I could give another upvote for your addition about the costs. Commented Sep 5, 2013 at 16:02
5

https://stackoverflow.com/questions/299068/how-slow-are-java-exceptions

The accepted answer on this question shows wrapping a function call in a try catch block costs less than 5% over a bare function call. Actually throwing and catching the exception caused runtime to balloon to more than 66x the bare function call. So if you expect the exception design to throw regularly then I would try to avoid it (in properly profiled performance critical code), however if the exceptional situation is rare then it isn't a big deal.

6
  • 3
    "if the exceptional situation is rare" - well there's a tautology right there. Exceptional means rare and that's precisely how exceptions should be used. Never should be part of the design or control flow. Commented Sep 4, 2013 at 14:07
  • 1
    Exceptions are not necessarily rare in practice, it's just accidental side effect. For example if you have bad UI people might cause the exception use case flow more often than the normal flow
    – Esailija
    Commented Sep 4, 2013 at 14:21
  • 2
    There are no exceptions being thrown in the question's code.
    – user40980
    Commented Sep 4, 2013 at 14:49
  • 2
    @JesseC.Slicer There are languages where it is not uncommon to see them used as flow control. As an example when iterating anything in python the iterator throws a stopiteration exception when it is done. Also in OCaml their standard library seems to be very "throw happy", it throws in a large number of situations that aren't rare(if you have a map and try to look up something that doesn't exist in the map it throws).
    – stonemetal
    Commented Sep 4, 2013 at 15:07
  • @stonemetal As does a Python dict, with a KeyError
    – Izkata
    Commented Sep 4, 2013 at 16:17
4

Instead of optimising - think of what your code is doing.

Adding the finally block is a different implementation - it means that you will logout on every exception.

Specifically - if login throws an exception, the behaviour in your second function will be different than your first.

If login and logout are not actually part of the function behaviour then I would suggest that the method should do one thing and one thing well:

    void func()
    {
            bool ret = dosomething();
            if(ret == false)
                return;

            ret = dosomethingelse();
            if(ret == false)
                return;

            dootherstuff();

    }

and should be in a function which is already encapsulated in a context which manages login / logout since these seem fundamentally different from what your main code is doing.

Your post is tagged as Java which I'm not super familiar with but in .net I would use a using block for this:

ie:

    using(var loginContext = CreateLoginContext()) 
    {
            // Do all your stuff
    }

And the login context has a Dispose method which will logout and clean up the resources.

Edit: I didn't actually answer the question!

I have no measurable evidence but I would not expect this to be any more expensive or certainly not significantly enough expensive for it to be worthy of premature optimisation.

I'm going to leave the rest of my answer because although not answering the question, I think it is helpful for the OP.

5
  • 1
    To complete your answer Java 7 introduced a try-with-resources statement that would be akin to your .net using construct, assuming that the resource in question implements the AutoCloseable interface.
    – haylem
    Commented Sep 4, 2013 at 13:28
  • I would even remove this ret variable, which is just assigned twice to be checked one line later. Make it if (dosomething() == false) return;.
    – ott--
    Commented Sep 4, 2013 at 15:08
  • Agreed but I wanted to keep the OP code the way it was provided.
    – Michael
    Commented Sep 4, 2013 at 15:27
  • @ott-- I assume the OP's code is a simplification of their use case - for example, they might have something more like ret2 = doSomethingElse(ret1), but that's not relevant to the question so it was removed.
    – Izkata
    Commented Sep 4, 2013 at 16:12
  • if (dosomething() == false) ... is bad code. Use the more intiutive if (!dosomething()) ... Commented Dec 17, 2014 at 8:01
1

Assumption: You are developing in C# code.

The quick answer is that there is no significant performance hit from using try/finally blocks. There is a performance hit when you throw and catch exceptions.

The longer answer is to see for your self. If you look at the underlying CIL code generated (e.g red-gate reflector then you can see the underlying CIL instructions generated and see the impact that way.

4
  • 12
    The question is tagged java. Commented Sep 4, 2013 at 13:17
  • Well spotted! ;) Commented Sep 4, 2013 at 13:27
  • 3
    Also, methods not capitalized, although that could just be good taste. Commented Sep 4, 2013 at 14:12
  • still a good answer if the question was c# :)
    – PhillyNJ
    Commented Sep 7, 2013 at 18:29
-2

As others already noted, Ttese code will have different results, if either dosomethingelse or dootherstuff throw an exception.

And yes, any function call can throw an exception, at least a StackOVerflowError! While it is rarly possible to handle these correctly (as any called cleanup function will probably have the same issue, in some cases (such as implementing locks for example) it is crucial to even handle that correctly...

1
  • 2
    this doesn't seem to offer anything substantial over prior 6 answers
    – gnat
    Commented Dec 17, 2014 at 8:20

Not the answer you're looking for? Browse other questions tagged or ask your own question.