112

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.

Glorfindel
  • 3,137
  • 6
  • 25
  • 33
Niklas Rosencrantz
  • 8,008
  • 17
  • 56
  • 95
  • 4
    In Java, why not put the return statement at the end of the try block? – kevin cline Jan 23 '12 at 18:52
  • See http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html for some thoughts on better practice – Kyle Sep 18 '12 at 07:11
  • 3
    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. – Pieter B Sep 18 '12 at 09:34
  • 3
    `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. – Mason Wheeler Apr 25 '13 at 01:21
  • 3
    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. – Rig Dec 19 '13 at 12:35
  • 1
    with Java use try with resources it's much more concise. – arisalexis Nov 12 '14 at 12:12
  • 4
    @MasonWheeler _"Ugly hacks"_ please, do explain what is bad about having an object handle it's own cleanup? – Baldrickk Jan 27 '15 at 11:45
  • 1
    @Baldrickk: I never said there's anything bad about that. How do you get that from what I wrote? – Mason Wheeler Jan 27 '15 at 12:08
  • 2
    @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 Feb 03 '15 at 17:23
  • @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. – Mason Wheeler Feb 03 '15 at 20:16
  • 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. – Kaiserludi Aug 24 '16 at 13:23
  • 2
    @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. – Justin Time - Reinstate Monica Dec 21 '16 at 00:40

9 Answers9

178

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.

ChrisF
  • 38,878
  • 11
  • 125
  • 168
  • 10
    *"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. – Ripped Off May 02 '12 at 12:59
  • 17
    @will - that's why I used the phrase "as possible". – ChrisF May 02 '12 at 13:00
  • 10
    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. – Neil Oct 24 '12 at 09:35
  • because sometimes all the way on top is as close as one can do – Newtopian Jan 27 '15 at 16:46
  • 1
    "just having a try / finally block is perfectly reasonable " was looking exactly for this answer. thank you @ChrisF – neal aise Jun 24 '15 at 12:07
40

The finally block is used for code that must always run, whether an error condition (exception) occurred or not.

The code in the finally block is run after the try block completes and, if a caught exception occurred, after the corresponding catch block completes. It is always run, even if an uncaught exception occurred in the try or catch block.

The finally block is typically used for closing files, network connections, etc. that were opened in the try block. The reason is that the file or network connection must be closed, whether the operation using that file or network connection succeeded or whether it failed.

Care should be taken in the finally block to ensure that it does not itself throw an exception. For example, be doubly sure to check all variables for null, etc.

yfeldblum
  • 1,532
  • 10
  • 9
  • 9
    +1: It's idiomatic for "must be cleaned up". Most uses of `try-finally` can be replaced with a `with` statement. – S.Lott Jan 23 '12 at 18:07
  • 13
    Various languages have extremely useful language-specific enhancements to the `try/finally` construct. C# has `using`, Python has `with`, etc. – yfeldblum Jan 23 '12 at 18:16
  • 5
    @yfeldblum - there is a subtle diff between `using` and `try-finally`, as the `Dispose` method won't be called by the `using` block if an exception happens in the `IDisposable` object's constructor. `try-finally` allows you to execute code even if the object's constructor throws an exception. – Scott Whitlock Feb 15 '12 at 16:27
  • 5
    @ScottWhitlock: That's a *good* thing? What are you trying to do, call a method on an unconstructed object? That's a billion kinds of bad. – DeadMG Feb 15 '12 at 16:55
  • 1
    @DeadMG: See also http://stackoverflow.com/q/14830534/18192 – Brian Apr 25 '13 at 03:21
  • 1
    @ScottWhitlock There is no difference at all, in fact, so long as you understand exactly how it's defined to work. The `with` construct is simply defined to construct the `IDisposable` object before the entry to `try`. If that's not what you want, you're free to use the `try` construct directly in a different way, say, by constructing the `IDisposable` object inside the `try` (and checking for `null` in the `finally`). – yfeldblum Apr 25 '13 at 15:27
17

An example where try... finally without a catch clause is appropriate (and even more, idiomatic) in Java is usage of Lock in concurrent utilities locks package.

  • Here's how it is explained and justified in API documentation (bold font in quote is mine):

    ...The absence of block-structured locking removes the automatic release of locks that occurs with synchronized methods and statements. In most cases, the following idiom should be used:

     Lock l = ...;
     l.lock();
     try {
         // access the resource protected by this lock
     } finally {
         l.unlock();
     }
    

    When locking and unlocking occur in different scopes, care must be taken to ensure that all code that is executed while the lock is held is protected by try-finally or try-catch to ensure that the lock is released when necessary.

gnat
  • 21,442
  • 29
  • 112
  • 288
  • Can I put `l.lock()` inside try? `try{ l.lock(); }finally{l.unlock();}` – RMachnik Jun 25 '15 at 18:55
  • 1
    technically, you can. I didn't put it there because semantically, it makes less sense. `try` in this snippet is intended to wrap resource access, why polluting it with something unrelated to that – gnat Jun 25 '15 at 18:58
  • 4
    You can, but if `l.lock()` fails, the `finally` block will still run if `l.lock()` is inside the `try` block. If you do it like gnat suggests, the `finally` block will only run when we **know** that the lock was acquired. – Wtrmute Mar 04 '16 at 16:32
13

At a basic level catch and finally solve two related but different problems:

  • catch is used to handle a problem that was reported by code you called
  • finally is used to clean up data/resources that the current code created/modified, no matter if a problem occurred or not

So both are related somehow to problems (exceptions), but that's pretty much all they have in common.

An important difference is that the finally block must be in the same method where the resources got created (to avoid resource leaks) and can't be put on a different level in the call stack.

The catch however is a different matter: the correct place for it depends on where you can actually handle the exception. There's no use in catching an exception at a place where you can do nothing about it, therefore it's sometimes better to simply let it fall through.

Joachim Sauer
  • 10,956
  • 3
  • 52
  • 45
  • 2
    Nitpick: *"... the finally block must be in the same method where the resources got created ... "*. It is certainly a *good idea* to do it that way, because it is easier to see there is no resource leak. However, it is not a necessary precondition; i.e. you don't *have to* do it that way. You can release the resource in the `finally` of a (statically or dynamically) enclosing try statement ... and still be 100% leak-proof. – Stephen C Apr 25 '13 at 04:32
9

In many languages a finally statement also runs after the return statement. This means you can do something like:

try {
  // Do processing
  return result;
} finally {
  // Release resources
}

Which releases the resources regardless of how the method was ended with an exception or a regular return statement.

Whether this is good or bad is up for debate, but try {} finally {} is not always limited to exception handling.

5

@yfeldblum has the correct answer: try-finally without a catch statement should usually be replaced with an appropriate language construct.

In C++, it's using RAII and constructors/destructors; in Python it's a with statement; and in C#, it's a using statement.

These are nearly always more elegant because the initialization and finalization code are in one place (the abstracted object) rather than in two places.

Neil G
  • 438
  • 2
  • 14
4

I might invoke the wrath of Pythonistas (don't know as I don't use Python much) or programmers from other languages with this answer, but in my opinion most functions should not have a catch block, ideally speaking. To show why, let me contrast this to manual error code propagation of the kind I had to do when working with Turbo C in the late 80s and early 90s.

So let's say we have a function to load an image or something like that in response to a user selecting an image file to load, and this is written in C and assembly:

enter image description here

I omitted some low-level functions but we can see that I've identified different categories of functions, color-coded, based on what responsibilities they have with respect to error-handling.

Point of Failure and Recovery

Now it was never hard to write the categories of functions I call the "possible point of failures" (the ones that throw, i.e.) and the "error recovery and report" functions (the ones that catch, i.e.).

Those functions were always trivial to write correctly before exception handling was available since a function that can run into an external failure, like failing to allocate memory, can just return a NULL or 0 or -1 or set a global error code or something to this effect. And error recovery/reporting was always easy since once you worked your way down the call stack to a point where it made sense to recover and report failures, you just take the error code and/or message and report it to the user. And naturally a function at the leaf of this hierarchy which can never, ever fail no matter how it's changed in the future (Convert Pixel) is dead simple to write correctly (at least with respect to error handling).

Error Propagation

However, the tedious functions prone to human error were the error propagators, the ones that didn't directly run into failure but called functions that could fail somewhere deeper in the hierarchy. At that point, Allocate Scanline might have to handle a failure from malloc and then return an error down to Convert Scanlines, then Convert Scanlines would have to check for that error and pass it down to Decompress Image, then Decompress Image->Parse Image, and Parse Image->Load Image, and Load Image to the user-end command where the error is finally reported.

This is where a lot of humans make mistakes since it only takes one error propagator to fail to check for and pass down the error for the entire hierarchy of functions to come toppling down when it comes to properly handling the error.

Further, if error codes are returned by functions, we pretty much lose the ability in, say, 90% of our codebase, to return values of interest on success since so many functions would have to reserve their return value for returning an error code on failure.

Reducing Human Error: Global Error Codes

So how can we reduce the possibility of human error? Here I might even invoke the wrath of some C programmers, but an immediate improvement in my opinion is to use global error codes, like OpenGL with glGetError. This at least frees the functions to return meaningful values of interest on success. There are ways to make this thread-safe and efficient where the error code is localized to a thread.

There are also some cases where a function might run into an error but it's relatively harmless for it to keep going a little bit longer before it returns prematurely as a result of discovering a previous error. This allows for such a thing to happen without having to check for errors against 90% of function calls made in every single function, so it can still allow proper error handling without being so meticulous.

Reducing Human Error: Exception-Handling

However, the above solution still requires so many functions to deal with the control flow aspect of manual error propagation, even if it might have reduced the number of lines of manual if error happened, return error type of code. It wouldn't eliminate it completely since there would still often need to be at least one place checking for an error and returning for almost every single error propagation function. So this is when exception-handling comes into the picture to save the day (sorta).

But the value of exception-handling here is to free the need for dealing with the control flow aspect of manual error propagation. That means its value is tied to the ability to avoid having to write a boatload of catch blocks throughout your codebase. In the above diagram, the only place that should have to have a catch block is the Load Image User Command where the error is reported. Nothing else should ideally have to catch anything because otherwise it's starting to get as tedious and as error-prone as error code handling.

So if you ask me, if you have a codebase that really benefits from exception-handling in an elegant way, it should have the minimum number of catch blocks (by minimum I don't mean zero, but more like one for every unique high-end user operation that could fail, and possibly even fewer if all high-end user operations are invoked through a central command system).

Resource Cleanup

However, exception-handling only solves the need to avoid manually dealing with the control flow aspects of error propagation in exceptional paths separate from normal flows of execution. Often a function which serves as an error propagator, even if it does this automatically now with EH, might still acquire some resources it needs to destroy. For example, such a function might open a temporary file it needs to close before returning from the function no matter what, or lock a mutex it needs to unlock no matter what.

For this, I might invoke the wrath of a lot of programmers from all sorts of languages, but I think the C++ approach to this is ideal. The language introduces destructors which get invoked in a deterministic fashion the instant an object goes out of scope. Because of this, C++ code which, say, locks a mutex through a scoped mutex object with a destructor need not manually unlock it, since it will be automatically unlocked once the object goes out of scope no matter what happens (even if an exception is encountered). So there's really no need for well-written C++ code to ever have to deal with local resource cleanup.

In languages that lack destructors, they might need to use a finally block to manually clean up local resources. That said, it still beats having to litter your code with manual error propagation provided you don't have to catch exceptions all over the freaking place.

Reversing External Side Effects

This is the most difficult conceptual problem to solve. If any function, whether it's an error propagator or point of failure causes external side effects, then it needs to roll back or "undo" those side effects to return the system back into a state as though the operation never occurred, instead of a "half-valid" state where the operation halfway succeeded. I know of no languages that make this conceptual problem much easier except languages that simply reduce the need for most functions to cause external side effects in the first place, like functional languages which revolve around immutability and persistent data structures.

Here finally is arguably the among the most elegant solutions out there to the problem in languages revolving around mutability and side effects, because often this type of logic is very specific to a particular function and doesn't map so well to the concept of "resource cleanup". And I recommend using finally liberally in these cases to make sure your function reverses side effects in languages that support it, regardless of whether or not you need a catch block (and again, if you ask me, well-written code should have the minimum number of catch blocks, and all catch blocks should be in places where it makes the most sense as with the diagram above in Load Image User Command).

Dream Language

However, IMO finally is close to ideal for side effect reversal but not quite. We need to introduce one boolean variable to effectively roll back side effects in the case of a premature exit (from a thrown exception or otherwise), like so:

bool finished = false;
try
{
    // Cause external side effects.
    ...

    // Indicate that all the external side effects were
    // made successfully.
    finished = true; 
}
finally
{
    // If the function prematurely exited before finishing
    // causing all of its side effects, whether as a result of
    // an early 'return' statement or an exception, undo the
    // side effects.
    if (!finished)
    {
        // Undo side effects.
        ...
    }
}

If I could ever design a language, my dream way of solving this problem would be like this to automate the above code:

transaction
{
    // Cause external side effects.
    ...
}
rollback
{
    // This block is only executed if the above 'transaction'
    // block didn't reach its end, either as a result of a premature
    // 'return' or an exception.

    // Undo side effects.
    ...
}

... with destructors to automate cleanup of local resources, making it so we only need transaction, rollback, and catch (though I might still want to add finally for, say, working with C resources that don't clean themselves up). However, finally with a boolean variable is the closest thing to making this straightforward that I've found so far lacking my dream language. The second most straightforward solution I've found for this is scope guards in languages like C++ and D, but I always found scope guards a little bit awkward conceptually since it blurs the idea of "resource cleanup" and "side effect reversal". In my opinion those are very distinct ideas to be tackled in a different way.

My little pipe dream of a language would also revolve heavily around immutability and persistent data structures to make it much easier, though not required, to write efficient functions that don't have to deep copy massive data structures in their entirety even though the function causes no side effects.

Conclusion

So anyway, with my ramblings aside, I think your try/finally code for closing the socket is fine and great considering that Python doesn't have the C++ equivalent of destructors, and I personally think you should use that liberally for places that need to reverse side effects and minimize the number of places where you have to catch to places where it makes the most sense.

0

As several other answers do a good job of explaining, try ... finally ... is indeed good practice in some situations. Here I want to point out that Python language itself gives you a strong hint that it is by giving you the with statement.

As the documentation points out, a with statement is semantically equivalent to a try ... except ... finally ... block. The __exit__() routine that is part of the context manager is always called when the block is completed (it's passed exception information if any exception occurred) and is expected to do cleanup. While it's possible also to handle exceptions at this point, it's quite normal always to let higher levels deal with the exception, and the API makes this easy:

If an exception is supplied, and the method wishes to suppress the exception (i.e., prevent it from being propagated), it should return a true value. Otherwise, the exception will be processed normally upon exit from this method.

Neil G suggests that try ... finally ... should always be replaced with a with. I disagree: which you should use depends on whether in that particular situation you feel that readers of your code would be better off seeing the cleanup code right there, or if it's more readable with the cleanup hidden in a an __exit__() method in the context manager object. For frequently-repeated situations where the cleanup is obvious, such as with open('somefile') as f: ..., with works better. For rarer situations where you're doing a more unusual cleanup (say, by deleting a file you failed to write completely) it may be better to have that stated explicitly at the call site.

cjs
  • 787
  • 4
  • 8
-69

Catching errors/exception and handling them in a neat manner is highly recommended even if not mandatory.

The reason I say this is because I believe every developer should know and tackle the behavior of his/her application otherwise he hasn't completed his job in a duly manner. There is no situation for which a try-finally block supersedes the try-catch-finally block.

I will give you a simple example: Assume that you have written the code for uploading files on the server without catching exceptions. Now, if for some reason the upload fails, the client will never know what went wrong. But, if you have caught the exception, you can display a neat error message explaining what went wrong and how can the user remedy it.

Golden rule: Always catch exception, because guessing takes time

Sathyajith Bhat
  • 117
  • 1
  • 1
  • 11
Pankaj Upadhyay
  • 5,060
  • 11
  • 44
  • 60
  • 25
    -1: In Java, a finally clause may be needed to release resources (e.g. close a file or release a DB connection). That is independent of the ability to handle an exception. – kevin cline Jan 23 '12 at 18:47
  • @kevincline, He is not asking whether to use finally or not...All he is asking is whether catching an exception is required or not....He knows what try , catch and finally does.....Finally is the most essential part, we all know that and why it's used.... – Pankaj Upadhyay Jan 23 '12 at 18:52
  • 67
    @Pankaj: your answer suggests that a `catch` clause should always be present whenever there is a `try`. More experienced contributors, including me, believe this is poor advice. Your reasoning is flawed. The method containing the `try` is not the only possible place the exception can be caught. It is often simplest and best to allow catch and report exceptions from the top-most level, rather than duplicating catch clauses throughout the code. – kevin cline Jan 23 '12 at 19:25
  • @kevincline, I believe the perception of the question on others part is bit different. The question was precisely as to, Should we catch an exception or not....And I answered in that regard. Handling exsception can be done in number of ways and not just try-finally. But, that was not the concern of OP. If raising an exception is good enough for you and other guys, then i must say best of luck. – Pankaj Upadhyay Jan 24 '12 at 05:48
  • 2
    With exceptions, you *want* the normal execution of statements to be interrupted (and without manually checking for success at each step). This is especially the case with deeply nested method calls - a method 4 layers inside some library can't just "swallow" an exception; it needs to be thrown back out through all the layers. Of course, each layer could wrap the exception and add additional info; this is often not done for various reasons, additional time to develop and unnecessary verbosity being the two biggest. – Daniel B Sep 18 '12 at 11:42
  • Java 7 allows Automatic Resource Management in the Try block, effectively removing most cases where a finally block is needed. – SnakeDoc Apr 25 '13 at 01:13
  • 4
    This is **actively bad advice**. _Never_ catch an exception unless you are prepared to deal with the underlying failure or _at least re-throw_ it. The absolute _worst_ codebase I have ever had to fix contained hundreds of idiotic placebo log-and-quash catch blocks peppered all across it that did nothing for user experience but leave corrupted state for other code to crash on, while actively _preventing_ higher-level code from detecting and recovering from the failures. Crashing immediately is a _more correct_ behavior than blindly quashing exceptions. – AJMansfield Mar 05 '21 at 20:41
  • Say I have a method that is supposed to save a document. All I care about is whether the document was saved or not, and that the app doesn’t crash if it cannot be saved. Exception handling should clean up mess that higher levels don’t know about, and then pass the failure on. – gnasher729 Dec 08 '22 at 17:42