Why use try … finally without a catch clause?

  • The classical way to program is with try ... catch. When is it appropriate to use try without catch?

    In Python the following appears legal and can make sense:

    try:
      #do work
    finally:
      #do something unconditional
    

    However, the code didn't catch anything. Similarly one could think in Java it would be as follows:

    try {
        //for example try to get a database connection
    }
    finally {
      //closeConnection(connection)
    }
    

    It looks good and suddenly I don't have to worry about exception types, etc. If this is good practice, when is it good practice? Alternatively, what are the reasons why this is not good practice or not legal? (I didn't compile the source. I'm asking about it as it could be a syntax error for Java. I checked that the Python surely compiles.)

    A related problem I've run into is this: I continue writing the function/method, at the end of which it must return something. However, it may be in a place which should not be reached and must be a return point. So, even if I handle the exceptions above, I'm still returning NULL or an empty string at some point in the code which should not be reached, often the end of the method/function. I've always managed to restructure the code so that it doesn't have to return NULL, since that absolutely appears to look like less than good practice.

    In Java, why not put the return statement at the end of the try block?

    I am sad that try..finally and try..catch both use the try keyword, apart from both starting with try they're 2 totally different constructs.

    `try/catch` is not "the classical way to program." It's *the classical C++ way to program,* because C++ lacks a proper try/finally construct, which means you have to implement guaranteed reversible state changes using ugly hacks involving RAII. But decent OO languages don't have that problem, because they provide try/finally. It's used for a very different purpose than try/catch.

    I see it a lot with external connection resources. You want the exception but need to make sure that you don't leave an open connection etc. If you caught it you would just rethrow it to the next layer anyway in some cases.

    with Java use try with resources it's much more concise.

    @MasonWheeler _"Ugly hacks"_ please, do explain what is bad about having an object handle it's own cleanup?

    @Baldrickk: I never said there's anything bad about that. How do you get that from what I wrote?

    @MasonWheeler Sorry, should probably have been "What ugly hacks are needed to get RAII to work, and why does handling it's own clean-up instead of relying on external 'finally' code make it "not a decent OO language"? If anything _I_ think it makes it _better_

    @Baldrickk: Again, I said nothing about cleanup. What I said was "guaranteed reversible state changes," which is a superset of "cleanup of locals." RAII can handle "cleanup of locals" just fine, but what about when you have to set a certain state, perform an operation, and then set the state back to the way it was before? There's no way to do that in C++ without creating an entire class (which you will probably instantiate a grand total of one place in your entire codebase) to have its destructor do it for you. It's a classic example of an abstraction inversion.

    the classical way to code C++ (and imho the only correct way to code in general) is to avoid exceptions at all means, as try-catch blocks with all their mandatory braces even for on-liner clutter the source with way to many lines unrelated to actual functionality, are slowing down execution and inferior to classical C error handling via return values and assertions.

    @MasonWheeler To be fair, RAII is a lot cleaner than `try`...`finally` when you're working with a commonly-used resource, it only becomes a problem when you get into issues like the abstraction inversion you mentioned in your third comment. The _real_ issue would be that C++ doesn't provide _both_ alternatives, so you have to use something overly complex in certain simple cases that shouldn't need their own classes.

  • ChrisF

    ChrisF Correct answer

    9 years ago

    It depends on whether you can deal with the exceptions that can be raised at this point or not.

    If you can handle the exceptions locally you should, and it is better to handle the error as close to where it is raised as possible.

    If you can't handle them locally then just having a try / finally block is perfectly reasonable - assuming there's some code you need to execute regardless of whether the method succeeded or not. For example (from Neil's comment), opening a stream and then passing that stream to an inner method to be loaded is an excellent example of when you'd need try { } finally { }, using the finally clause to ensure that the stream is closed regardless of the success or failure of the read.

    However, you will still need an exception handler somewhere in your code - unless you want your application to crash completely of course. It depends on the architecture of your application exactly where that handler is.

    *"and it is better to handle the error as close to where it is raised as possible."* eh, it depends. If you can recover and still complete the mission (so to speak), yes of course. If you cannot, better to let the exception go all the way to the top, where (likely) user intervention will be required to deal with what happened.

    @will - that's why I used the phrase "as possible".

    Good answer, but I would add an example: Opening a stream and passing that stream to an inner method to be loaded is an excellent example of when you'd need `try { } finally { }`, taking advantage of finally clause to ensure stream is ultimately closed regardless of success/failure.

    because sometimes all the way on top is as close as one can do

    "just having a try / finally block is perfectly reasonable " was looking exactly for this answer. thank you @ChrisF

License under CC-BY-SA with attribution


Content dated before 6/26/2020 9:53 AM