Should you throw an exception, or return null? Should you use checked or unchecked exceptions? For many novice to mid-level developers, exception handling tends to be an afterthought. Their typical pattern is usually a simple try/catch/printStackTrace(). When they try to get more creative, they usually stumble into one or more common exception handling antipatterns.
The antipattern concept became popular in the software development community with the release of AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis in 1998. An antipattern draws on real-world experience to identify a commonly occurring programming mistake. It describes the general form of the bad pattern, identifies its negative consequences, prescribes a remedy, and helps define a common vocabulary by giving each pattern a name.
In this article, we'll discuss some fundamental concepts about the different types of Java exceptions and their intended uses. We'll also cover basic logging concepts, especially as they relate to exception handling. Finally, instead of prescribing what to do, we'll focus on what not to do, and take a look at a dozen common exception-handling antipatterns that you are almost certain to find somewhere in your code base.
Basic Exception Concepts
One of the most important concepts about exception handling to understand is that there are three general types of throwable classes in Java: checked exceptions, unchecked exceptions, and errors.
Checked exceptions are exceptions that must be declared in the throws clause of a method. They extend Exception and are intended to be an "in your face" type of exceptions. A checked exception indicates an expected problem that can occur during normal system operation. Some examples are problems communicating with external systems, and problems with user input. Note that, depending on your code's intended function, "user input" may refer to a user interface, or it may refer to the parameters that another developer passes to your API. Often, the correct response to a checked exception is to try again later, or to prompt the user to modify his input.
Unchecked exceptions are exceptions that do not need to be declared in a throws clause. They extend RuntimeException. An unchecked exception indicates an unexpected problem that is probably due to a bug in the code. The most common example is a NullPointerException. There are many core exceptions in the JDK that are checked exceptions but really shouldn't be, such as IllegalAccessException and NoSuchMethodException. An unchecked exception probably shouldn't be retried, and the correct response is usually to do nothing, and let it bubble up out of your method and through the execution stack. This is why it doesn't need to be declared in a throws clause. Eventually, at a high level of execution, the exception should probably be logged (see below).
Errors are serious problems that are almost certainly not recoverable. Some examples are OutOfMemoryError, LinkageError, and StackOverflowError.
Creating Your Own Exceptions
Most packages and/or system components should contain one or more custom exception classes. There are two primary use cases for a custom exception. First, your code can simply throw the custom exception when something goes wrong. For example:
throw new MyObjectNotFoundException("Couldn't find
object id " + id);
Second, your code can wrap and throw another exception. For example:
catch (NoSuchMethodException e) {
throw new MyServiceException("Couldn't process
request", e);
}
Wrapping an exception can provide extra information to the user by adding your own message (as in the example above), while still preserving the stack trace and message of the original exception. It also allows you to hide the implementation details of your code, which is the most important reason to wrap exceptions. For instance, look at the Hibernate API. Even though Hibernate makes extensive use of JDBC in its implementation, and most of the operations that it performs can throw SQLException, Hibernate does not expose SQLException anywhere in its API. Instead, it wraps these exceptions inside of various subclasses of HibernateException. Using the approach allows you to change the underlying implementation of your module without modifying its public API.
Exceptions and Transactions
EJB 2
The creators of the EJB 2 specification decided to make use of the distinction between checked and unchecked exceptions to determine whether or not to roll back the active transaction. If an EJB throws a checked exception, the transaction still commits normally. If an EJB throws an unchecked exception, the transaction is rolled back. You almost always want an exception to roll back the active transaction. It just helps to be aware of this fact when working with EJBs.
EJB 3
To somewhat alleviate the problem that I just described, EJB 3 has added an ApplicationException annotation with a rollback element. This gives you explicit control over whether or not your exception (either checked or unchecked) should roll back the transaction. For example:
@ApplicationException(rollback=true)
public class FooException extends Exception
...
Message-Driven Beans
Be aware that when working with message-driven beans (MDBs) that are driven by a queue, rolling back the active transaction also places the message that you are currently processing back on the queue. The message will then be redelivered to another MDB, possibly on another machine, if your app servers are clustered. It will be retried until it hits the app server's retry limit, at which point the message is left on the dead letter queue. If your MDB wants to avoid reprocessing (e.g., because it performs an expensive operation), it can call getJMSRedelivered() on the message, and if it was redelivered, it can just throw it away.
Logging
When your code encounters an exception, it must either handle it, let it bubble up, wrap it, or log it. If your code can programmatically handle an exception (e.g., retry in the case of a network failure), then it should. If it can't, it should generally either let it bubble up (for unchecked exceptions) or wrap it (for checked exceptions). However, it is ultimately going to be someone's responsibility to log the fact that this exception occurred if nobody in the calling stack was able to handle it programmatically. This code should typically live as high in the execution stack as it can. Some examples are the onMessage() method of an MDB, and the main() method of a class. Once you catch the exception, you should log it appropriately.
The JDK has a java.util.logging package built in, although the Log4j project from Apache continues to be a commonly-used alternative. Apache also offers the Commons Logging project, which acts as a thin layer that allows you to swap out different logging implementations underneath in a pluggable fashion. All of these logging frameworks that I've mentioned have basically equivalent levels:
FATAL: Should be used in extreme cases, where immediate attention is needed. This level can be useful to trigger a support engineer's pager.
ERROR: Indicates a bug, or a general error condition, but not necessarily one that brings the system to a halt. This level can be useful to trigger email to an alerts list, where it can be filed as a bug by a support engineer.
WARN: Not necessarily a bug, but something someone will probably want to know about. If someone is reading a log file, they will typically want to see any warnings that arise.
INFO: Used for basic, high-level diagnostic information. Most often good to stick immediately before and after relatively long-running sections of code to answer the question "What is the app doing?" Messages at this level should avoid being very chatty.
DEBUG: Used for low-level debugging assistance.
If you are using commons-logging or Log4j, watch out for a common gotcha. The error, warn, info, and debug methods are overloaded with one version that takes only a message parameter, and one that also takes a Throwable as the second parameter. Make sure that if you are trying to log the fact that an exception was thrown, you pass both a message and the exception. If you call the version that accepts a single parameter, and pass it the exception, it hides the stack trace of the exception.
When calling log.debug(), it's good practice to always surround the call with a check for log.isDebugEnabled(). This is purely for optimization. It's simply a good habit to get into, and once you do it for a few days, it will just become automatic.
Do not use System.out or System.err. You should always use a logger. Loggers are extremely configurable and flexible, and each appender can decide which level of severity it wants to report/act on, on a package-by-package basis. Printing a message to System.out is just sloppy and generally unforgivable.
catch (NoSuchMethodException e) {
e.printStackTrace();
throw new MyServiceException("Blah", e);
}
All of the above examples are equally wrong. This is one of the most annoying error-handling antipatterns. Either log the exception, or throw it, but never do both. Logging and throwing results in multiple log messages for a single problem in the code, and makes life hell for the support engineer who is trying to dig through the logs.
Throwing Exception
Example:
public void foo() throws Exception {
This is just sloppy, and it completely defeats the purpose of using a checked exception. It tells your callers "something can go wrong in my method." Real useful. Don't do this. Declare the specific checked exceptions that your method can throw. If there are several, you should probably wrap them in your own exception (see "Throwing the Kitchen Sink" below.)
Throwing the Kitchen Sink
Example:
public void foo() throws MyException,
AnotherException, SomeOtherException,
YetAnotherException
{
Throwing multiple checked exceptions from your method is fine, as long as there are different possible courses of action that the caller may want to take, depending on which exception was thrown. If you have multiple checked exceptions that basically mean the same thing to the caller, wrap them in a single checked exception.
This is generally wrong and sloppy. Catch the specific exceptions that can be thrown. The problem with catching Exception is that if the method you are calling later adds a new checked exception to its method signature, the developer's intent is that you should handle the specific new exception. If your code just catches Exception (or worse, Throwable), you'll probably never know about the change and the fact that your code is now wrong.
catch (NoSuchMethodException e) {
e.printStackTrace();
return null;
} // Man I hate this one
Although not always incorrect, this is usually wrong. Instead of returning null, throw the exception, and let the caller deal with it. You should only return null in a normal (non-exceptional) use case (e.g., "This method returns null if the search string was not found.").
Catch and Ignore
Example:
catch (NoSuchMethodException e) {
return null;
}
This one is insidious. Not only does it return null instead of handling or re-throwing the exception, it totally swallows the exception, losing the information forever.
Throw from Within Finally
Example:
try {
blah();
} finally {
cleanUp();
}
This is fine, as long as cleanUp() can never throw an exception. In the above example, if blah() throws an exception, and then in the finally block, cleanUp() throws an exception, that second exception will be thrown and the first exception will be lost forever. If the code that you call in a finally block can possibly throw an exception, make sure that you either handle it, or log it. Never let it bubble out of the finally block.
Always try to group together all log messages, regardless of the level, into as few calls as possible. So in the example above, the correct code would look like:
LOG.debug("Using cache policy A, using retry policy B");
Using a multi-line log message with multiple calls to log.debug() may look fine in your test case, but when it shows up in the log file of an app server with 500 threads running in parallel, all spewing information to the same log file, your two log messages may end up spaced out 1000 lines apart in the log file, even though they occur on subsequent lines in your code.
Unsupported Operation Returning Null
Example:
public String foo() {
// Not supported in this implementation.
return null;
}
When you're implementing an abstract base class, and you're just providing hooks for subclasses to optionally override, this is fine. However, if this is not the case, you should throw an UnsupportedOperationException instead of returning null. This makes it much more obvious to the caller why things aren't working, instead of her having to figure out why her code is throwing some random NullPointerException.
InterruptedException is a clue to your code that it should stop whatever it's doing. Some common use cases for a thread getting interrupted are the active transaction timing out, or a thread pool getting shut down. Instead of ignoring the InterruptedException, your code should do its best to finish up what it's doing, and finish the current thread of execution. So to correct the example above:
catch (MyException e) {
if (e.getCause() instanceof FooException) {
...
The problem with relying on the result of getCause is that it makes your code fragile. It may work fine today, but what happens when the code that you're calling into, or the code that it relies on, changes its underlying implementation, and ends up wrapping the ultimate cause inside of another exception? Now calling getCause may return you a wrapping exception, and what you really want is the result of getCause().getCause(). Instead, you should unwrap the causes until you find the ultimate cause of the problem. Apache's commons-lang project provides ExceptionUtils.getRootCause() to do this easily.
Conclusion
Good exception handling is a key to building robust, reliable systems. Avoiding the antipatterns that we've outlined here helps you build systems that are maintainable, resilient to change, and that play well with other systems.
Do you agree with Tim's catalog of exception-handling worst practices?
Showing messages 1 through 41 of 41.
Most of the examples in this article expose the design flaws of Java.
2008-05-07 11:52:29 cpk1971
[Reply | View]
Some general comments:
1. Many of these antipatterns (Throwing Exception, Kitchen Sink, Catching Exception, Log and Return Null) are caused by Java's insistence on checked exceptions. I wrote in .NET for several years and never saw code like this:
try {
// stuff
} catch (Exception e) {}
NEVER. If you didn't handcuff people with checked exceptions, people wouldn't react in this way.
Checked exceptions are simply evil. James Gosling is simply wrong on this point (it's about the only thing he's ever been wrong about, but boy is he wrong). The benefit it gives you is massively outweighed by the problems it causes, not the least of which are the behaviors it encourages in mediocre programmers.
2. Log and throw is OK if worker classes have their own logs. This way you can see the exception in context with the other processing steps. You don't want logs of intermediate processing steps combined in high-level logs anyway, so really this is just an argument against putting everything in the same log.
3. Throwing From Finally is a flaw in the try/catch/finally, and you are basically just screwed. This can cause serious, serious problems and simply logging the error is insufficient. Java gives us no other alternatives, however.
Java is a decent platform, but when it comes to exceptions it is made of total fail.
I think that all exceptions should be runtime exceptions because they are exceptional!! You shouldn't force anyone outside of your API to catch and deal with an exception...it should be up to you to deal with them..
If you get an IOException in your API then you should catch it and deal with it...If you have no other options to deal with the IO problem then you should throw a runtime exception because it most likely means that there Harddrive in on the way out or there modem is not connected...etc...etc. HOWEVER....Most of the time you can't do anything anyway...so you catch the exception and throw it...MAKE IT A RUNTIME because no one else is going to be able to do anything with neither so it ***NEEDS TO FAIL*** the application and it will give you a stacktrace so that the developer can deal with it...
1. Exceptions slow down code!
2. Forcing developers to handle the exception also means you get completely irrelevant try catches all over the place...
*** About 99% of the time they just catch your exception and throw it with your exception message attached to it (what is the point of that!!!???). Cluttered code!***
3. Throwing a runtime exception means that a developer using your API can choose whether or not to deal with the Exception...they may be able to do something AND (AND!!!) they have a choice!?
4. I use C/C++ and the number 1 (absolute number 1) pain in the ar$e problem with java is the amount of forced exception handling code that gets rammed at you.
All exceptions should be runtime exceptions...show me some *real* code that benefits from caught exceptions instead of caught exceptions (show me some that you have done and is out there and can be looked at)
;)
New to Java
2007-11-25 14:42:35 vanlimburga
[Reply | View]
I am very new to Java and found the article really useful - I have one (naive?) question -
In other discussion threads there was alot of issue with only producing the stack dump once - would an approach to this be (apologize in advance for any bad coding practice or where code is commented out - still working these bits out):
public class JadeSessionException extends RuntimeException {
static final long serialVersionUID = 76523;
private boolean logged = false;
public void logDetails (){
// prevent multiple stack dumps from being generated
Throwable lException = this;
while (lException!=null){
// Is the execption "one of ours"
if (!lException.getClass().getName().substring(4).contentEquals("Jade")) break;
// need to check value of "logged" - if true then set this to true also - then break
// TypeCast exception to be "one of ours" - check the "logged" flag
// if ("on of ours".logged) {
// logged = true;
// return;
// }
//
lException = lException.getCause();
}
Don't throw RuntimeException either
2006-07-26 11:39:17 dserodio
[Reply | View]
Besides not throwing Exception, you should also never throw RuntimeException, Error, or even worse, Throwable.
Why ain't these classes abstract?
Don't throw RuntimeException either
2007-06-12 01:37:18 agnus
[Reply | View]
Besides not throwing Exception, you should also never throw RuntimeException, Error, or even worse, Throwable.
I beg to disagree. Suppose a program that is created and executed in a perfect environment, where there won't be any errors either from the code itself, the hardware or the operator. Such a program should not need a single try / catch / throw statement within it's sources.
However the world we live in is imperfect and at any given moment / situation there are infinite problems that can arise. Therefore if we wanted to make this program as secure as possible we could declare near infinite exception throws at any given method! Ofcource that would be madness and that is why checked-exceptions are evil.
Exceptions should reflect exactly that.. exceptional situations and I should be able to ignore any of them - either because I am in perfect knowledge, or because I am ignorant, or because I am plain lazy -.
Don't throw RuntimeException either
2006-07-26 12:35:27 timmccune
[Reply | View]
I find this article incredibly relevant to many, however, I do have a note to add.
Usually you would wrap exceptions, and catch them as late as possible, but if you happen to troubleshoot from stack traces, you usually see :
xx.xx.Exception: baad user!
trace....
trace...
caused by xx.xx.Exception: baad programmer!
trace..
AND 42 more.... (This is the culprit!!)
The fact that wrapped exceptions traces and especially the root cause exception traces are hidden from the printout is a serious mistake in the implementation.
I know I can read the message, but the call stack is reported top-down, and perhaps not until the bottom of the call stack, which is where the exception occurred.
Before the java.lang.Exception was capable of storing a cause, lots of information was silently lost, but I believe that the way the implementation now handles nested exceptions and their traces is basically a headless implementation.
Now this may be just an opinion, but some programmers actually log the error BECAUSE it may never show otherwise (I've met a few), which make the stack trace even worse because you cannot easily mark the boundaries of the problem.
The '... and 42 more' means the rest of the remaining 42 lines of the exception's trace match the last 42 lines of the enclosing exception's trace. No information has been lost.
I personally prefer this way because if you're reading the log from the bottom (e.g. tail -f) then the root cause is the easiest thing to find.
http://java.sun.com/javase/6/docs/api/java/lang/Throwable.html#printStackTrace() might explain it better than I can.
The best thing to do in a situation like this is probably to unwrap the root cause before you rewrap it.
good article
2006-04-13 01:17:27 theodoor
[Reply | View]
A clear and inspiring article. Very good and very helpfull. I have adviced my colleagues to read it ti
Very Good
2006-04-12 09:06:36 waelson
[Reply | View]
Really, very very good!
Good Article
2006-04-10 12:02:32 dblair
[Reply | View]
A good article Tim!
My first thought was "this is all common sense...who cares.", but once I started getting into the patterns there was more than one that I wouldn't have thought about the consequences if they weren't pointed out in this article.
Good stuff!
DB
Again on log and throw
2006-04-09 03:23:45 fabriziogiudici
[Reply | View]
An excellent article which should be part of the coding rules of any Java project.
But I'd like to comment further on the log-and-throw. While generally speaking I do agree that a thrown exception should not be logged, there's a practical exception.
Consider a distributed application with Clients and Servers. The Client objects are deployed on different container (and hosts) than the Server objects, so they basically log to different files (and possibly with different settings).
If you only throw, the exception would be caught by Client objects and only logged to Client hosts. With an application which is currently in production and in mantaince mode, I often receive logs attached to incident reports from Server objects, while reporting from Clients objects is often incomplete (they are managed by different operators). In the end, if I didn't log also in Server objects, I'd completely lose exception information.
Again on log and throw
2006-04-09 08:38:04 timmccune
[Reply | View]
Agreed, in general. This is why the EJB spec differentiates between application exceptions and system exceptions. System exceptions are handled in the manner that you described. Application exceptions should not be logged on the server side.
Again on log and throw
2006-04-09 15:59:17 fabriziogiudici
[Reply | View]
BTW, I'm referring to a non-J2EE application, for which there is no difference between application and system exceptions.
Again on log and throw
2006-04-09 03:26:12 fabriziogiudici
[Reply | View]
The "ignoring InterruptedException" section is wrong because it fails to restore the current threads interrupted status in the InterruptedException catch block. Either rethrow or restore the status.
FYI: Brian Goetz published an article in developerWorks about a month after this article on just the subject of handling InterruptedException.
The long and short of it:
try {
// ... something that can throw ...
}
catch (InterruptedException e) {
// Restore the interrupted status
Thread.currentThread().interrupt();
}
Use toString instead of getMessage
2006-04-07 05:32:10 ricon
[Reply | View]
imo you should add one point.
Instead of getMessage() which may return null, which in some cases may lead to useless output or worse NPEs, use toString, which returns the Throwable's classname + getLocalizedMessage if it is not null.
In this way you will always get at least the information which exception arised.
Use toString instead of getMessage
2006-04-07 09:18:31 timmccune
[Reply | View]
Good point. Thanks for the suggestion.
Log and Throw in a Session Facade
2006-04-07 03:49:08 jyanez
[Reply | View]
Congratulations, this is a good a article.
I think that to use Log and Thrown in a Session Facade is correct. The SessionFacade needs register the exception and it needs throws another exception to comunicate to the presentation layer the problem.
An alternative is to log in the presentation layer, but I think that is incorrect. The presentation layer is really another application
Regards, Javier Yáñez
Log and Throw in a Session Facade
2006-04-07 09:21:14 timmccune
[Reply | View]
It's been too long since I read the EJB2 spec, so I'm not sure what it says on this, but the EJB3 spec mandates that if an EJB throws a system exception, the EJB container must log the error and then throw it back to the client. If an EJB throws an application exception, the container should just throw it. This makes sense to me. Regardless, your EJB should not do any log and throw on its own.
Log and Throw in a Session Facade
2006-04-07 11:13:45 jyanez
[Reply | View]
I agree. When I writed the comment I'm thinking in a typical situation of a Session Facade catching SQLexceptions of a DAO. SQLExceptions are system exceptions and the Session Facade must do Log and Throw. Application exceptions must not do Log and Thrown, you're right.
Why we need NoSuchMethodException?
2006-04-06 21:56:43 carfield
[Reply | View]
Why we don't just don't implement that method? If this is required by the interface, why we implement an interface but not complete the contact?
Why we need NoSuchMethodException?
2006-04-10 07:53:47 dspencer73
[Reply | View]
You might not be ready to implement that method.
You might be implementing an interface with 5 methods, but want to run some test code on how you've implemented just three of them. But, before you can do that, you must implement the other two, at least trivially.
This is especially true on a large project where you are sharing the development effort with an entire team.
In these cases, it is better to throw an exception than stub out the method with a null return.
Why we need NoSuchMethodException?
2006-04-10 23:09:29 jwenting
[Reply | View]
Or you may have a need to implement an interface that you can't split up but need only 90% of its functionality.
This can easily be the case in large systems where an interface with say 5 methods should ideally have been 2 interfaces (maybe the second extending the first) but changing it now would break too much code (potentially hundreds or thousands of classes, possibly classes not under your control).
I've encountered such situations myself, where an interface declared a method that's logically part of that interface (say an interface defining CRUD operations on DAOs of some sort) but there are read-only entities. In order to have a common system of display logic those read-only entities need implement the interface but the creation and update methods make no sense for them.
Rather than letting them fail silently (of course an option) I'd prefer to throw an UnsupportedOperationException (rather than NoSuchMethodException) in such cases. Makes it immediately clear to the author of the class trying to do that update that his action isn't supported, instead of potentially having him look for days or weeks for the reason why the updates he sent to the system never were stored.
I use log and throw
2006-04-06 08:33:39 riccardocossu
[Reply | View]
I often use log and throw, but not in the way you post it; I use it like this:
This way you don't print multiple stacktraces but keep track of the context in which the exception happened, along with some possibly meningful info, maybe about what method threw the Exception.
I think it is clearer than having to lookup the line where the exception was thrown.
Regards, Riccardo
I use log and throw
2006-04-06 09:33:54 timmccune
[Reply | View]
But in your pattern, you will still print multiple stack traces because when you pass SomeOtherException to log.error further up the stack, you will see its stack trace plus the stack trace of the original exception. Providing some meaningful info, maybe about what method threw the Exception is a great practice to follow, but that's what the message parameter to the wrapping exception is for. Why do the same thing twice? Just look at your code; you have copy/pasted "I got exception" and e.getMessage() all in the span of 2 lines. That should clue you into the fact that something is not right there.
Your example also brings up another antipattern that I didn't mention in the article (2 antipatterns in one example, nice job. :) There is no reason to append e.getMessage() to the message parameter when you're creating SomeOtherException. The message is contained in the wrapped exception, and logging the wrapped exception will still produce the original exception message, along with the original stack trace. There's no good reason for the user to have to see it twice.
I use log and throw
2006-04-07 05:43:58 riccardocossu
[Reply | View]
Well, that was a little example written in no time with no editor (that's why copy & paste).
As for the multiple stack trace it simply is not true as long as you follow the same pattern unitl top of the stack; I completely agree that you should not print stack trace and rethrow.
As for printing the message twice or more it depends on how you configure the log system; for example you could print some kind of exception you want to keep track in another separate log (and turn it on and off as needed). The way you propose you would have the stack trace only in the "big" log a the top of the stack, which probably is what you want, but not always what I want; also you could use various level of logging other tahn erorr (info, warning or what) to achieve greater flexibility (in the example I used only error, but again "no time, no editor").
I use log and throw
2006-05-08 07:57:21 jimothy
[Reply | View]
At some point (perhaps at multiple points, as you "follow the same pattern [until the] top of the stack"), aren't you going to log SomeOtherException? Thus, you have logged the stack trace multiple times.
I use log and throw
2006-04-06 10:19:48 greeneyed
[Reply | View]
I used to fall for this one in my web framework, and it became quite annoying to see stacktraces with causes repeated again and again. Now what I do is I create the new exception with the proper message, use initCause(origException), the same as creating it with the original exception I guess, and throw the new exception. This keeps going until the code that needs to deal with the exception receives it.
So now I get a long stacktrace full of "caused by..." but that has the exceptions and the traces just showed once and with the exceptions in an easy to follow order (cause->consequence).
Throwing from finally is not always wrong
2006-04-06 06:41:59 christian_schlichtherle
[Reply | View]
I really appreciate this article. However, I think it shouldn't generally discourage throwing from a finally clause. The fact that the exception in the finally clause takes precedence over the exception in the try clause is intentional and sometimes very useful. Example:
FileOutputStream fos = new FileOutputStream("foo.bar");
try {
// Do something with fos here...
} finally {
fos.close();
}
This is an idiom which shows how to treat a file stream correctly, because:
It always calls close(), no matter what happened. This is important, because if close() is not called, your operating system is still using a file descriptor for it until your application terminates. This may render your application non-scalable if it is a long-running server app. In addition, on platforms like WIndows files are locked for deletion or changes by all processes until the application has finally closed it.
Normally, close() always succeeds. If it doesn't, then most probably because buffered I/O was used (not in this example) and flushing the buffer failed. In this case, it is perfectly OK that the exception takes precedence.
The example I can be generalized: Whenever you have an object that deals with an external resource, you must make sure to release it. This is to be done in a finally-clause - everything else does not work. If this finally-clause then throws another exception, it is for a good reason and you should not ignore this.
For the example I've written this means that if you need to catch the IOException you need to enclose the entire try-finally-clause with another try-catch-clause. This ensures that close() is always called.
Regards,
Christian
Throwing from finally is not always wrong
2007-07-04 05:01:30 yarden_nb
[Reply | View]
I read the debate with a lot of interest. The bottom line I see is that there is no clean way out: if you catch an exception from the close(), you may miss an error (logging is fine if you have a good logging facitlity in your project; this is not always the case). If you don't, an exception from the close() may hide an throwable from the try-block (I deliberately write "throwable"; you missed the possibility that the exception from the try block may be something completely unrelated to the problem causing the close; say, out-of-memory).
Since both ways are potentailly harmful, I wonder if it's so wrong to do the no-no, and put the close() outside finally:
FileOutputStream fos = new FileOutputStream("foo.bar");
// Do something with fos here...
fos.close();
If an exception was thrown from the "do something with fos...", it will not be lost. If an exception was thrown from the close(), it will not be lost either. What do we lose? Of course, we may fail to close the file. But this happens in a path where an error was thrown anyway, and presumably reported to the user/developer - so it's not that a problem has been passed unnoticed.
I'm not claiming that this state of affairs is better than the two possibilities with the finally. But since each is bad in its own way, I often opt for this one - at least it's the cleanest in terms of code simplicity...
Throwing from finally is not always wrong
2006-04-06 09:45:15 timmccune
[Reply | View]
I think you may have misunderstood my point on this antipattern. I wasn't trying to say that the exception that can get thrown from the finally block should be ignored. My point was that you should almost never just ignore an exception, and if you allow the code in the finally block to throw an exception, you have just ignored the first exception, and its information is lost forever.
I'm also not trying to suggest that finally blocks are bad. In your example, of course the stream needs to always get closed in a finally block. You just need to wrap that close inside of another try/catch, so that its exception can't override the first exception.
If the exception in the finally block is certain to be more important than the code within the try (which should almost never be the case), then you could follow a pattern like this:
FileOutputStream fos = ...
IOException origEx = null;
try {
//Do something with fos here...
} catch (IOException e) {
origEx = e;
} finally {
try {
fos.close();
} catch (IOException closeEx) {
if (origEx != null) {
// Make sure the original exception isn't lost
log.error("blah", origEx);
}
throw closeEx;
}
throw origEx;
}
Throwing from finally is not always wrong
2006-04-06 15:08:36 christian_schlichtherle
[Reply | View]
Sorry, I disagree:
First, this example is overdone: Nobody should be encouraged to produce so many lines of code just to close a stream.
Second, you are assuming that an exception in the try-block is more important than the exception in the finally-block. But if for some reason a finally-block throws another exception then it should actually take precedence because it is the last exception that occured. This is what the Java language specification says and there is nothing wrong with this definition. If it were preferrable the other way round, I'm sure the Java language specification would say so, but it doesn't.
How well this specification actually works can be seen with FileInput/OutputStream: The close method of these classes actually never throws an IOException (because the system's POSIX close() call never fails on a valid file descriptor). The throws-clause is just inherited from Input/OutputStream. These classes add the throws-statement to the close method primarily in order to allow for reliable output buffering: If an output stream is decorated by a buffered stream, then the close method may actually throw another exception when trying to flush the buffer on close. In this case, it makes sense to have the IOException thrown by the close method in a finally-block take precedence, because this exception reflects the last operation which happened to your file - flushing the buffer to disk while closing.
Throwing from finally is not always wrong
2006-04-06 15:15:30 timmccune
[Reply | View]
I don't really care whether the exception in the try block or the exception in the finally block is more important. The only point that I'm trying to get across, and that you seem to keep missing, is that it's bad practice to discard either one of the exceptions. Make sure you catch them both and handle them both, either by logging them both, or logging one and throwing the other.
Throwing from finally is not always wrong
2006-04-06 16:28:06 christian_schlichtherle
[Reply | View]
But this is the point: If and only if an exception is thrown in a finally clause, then this most likely marks an event of a higher priority which makes your initial exception irrelevant.
To see this principle in action, here's a full example of how to write a file using a buffered output stream:
try {
OutputStream out = new BufferedOutputStream(new FileOutputStream("foo.bar"));
try {
// write to out here...
} finally {
out.close();
}
} catch (IOException ioe) {
logger.severe("ouch", ioe);
}
As you can see, this is a short and elegant solution: First, close() is always called unless the file couldn't get opened. Second, if anything goes wrong, no matter where and why, the exception is logged. Third, if and only if close() fails, its IOException takes precedence over any IOException that may have been generated in the try-block, effectively discarding it. This is perfectly OK as the initial exception has become irrelevant upon the dawn of an IOException in close().
Of course, this principle applies only where the try-block and the finally-block operate on the same (external) resource (files in this case). Ultimately, this use-case is what finally has been designed for. In other cases it should probably not be applied. In these other cases I also completely agree to you saying that one should never simply ignore exceptions.
Throwing from finally is not always wrong
2006-04-19 21:51:47 infernoz
[Reply | View]
The correct code is:
{ // Optional local clause.
OutputStream out = null;
try {
out = new BufferedOutputStream(new FileOutputStream("foo.bar"));
// write to out here...
} catch (IOException ioe1) {
logger.severe("bad io", ioe1);
} finally {
if (out!=null) {
try {
out.flush(); // required, because close does not flush!
out.close();
} catch (IOException ioe2) {
logger.severe("close failed", ioe2);
}
}
}
} // end of clause
Throwing from finally is not always wrong
2006-04-10 05:30:50 captainjester
[Reply | View]
Wrong. The fact that you can't close a stream is totally irrelevent compared to a FileNotFoundException. Most exceptions that will occur in a finally block are of the cleanup type. They might be important, but it is more important if an exception occurred in the original try block.
Throwing from finally is not always wrong
2006-04-06 16:40:08 timmccune
[Reply | View]
In your isolated example of closing a file descriptor, the exception thrown from within the finally is probably more important. However, in my experience, every single time I've come across this antipattern, the exception in the try block was the more important one, and typically was the cause of the exception in the finally block. Regardless, there is still no excuse for just throwing away the original exception.