Summary
Java's checked exceptions sometimes force you to catch a checked exception that you believe will never be thrown. Best practice dictates that you wrap that in an unchecked exception and rethrow it, just in case. What exception class do you wrap with in that case?
Advertisement
In my Failure Happens: Deal with It! talk, which I gave last month at JavaPolis, I described a situation I encounter fairly regularly as a Java programmer. The compiler forces me to catch a checked exception that I believe will in all likelihood never be thrown. For example, in our web application that runs Artima, we always encode URLs with UTF-8 encoding by passing "UTF-8" to java.net.URLEncoder.encode(). Here's an example:
private static final String UTF8_CHAR_ENCODING = "UTF-8";
// ...
String encodedURL;
try {
encodedURL = URLEncoder.encode(url, UTF8_CHAR_ENCODING);
}
catch (UnsupportedEncodingException e) {
// Should never happen
throw new RuntimeException(e);
}
// ...
It is my belief that "UTF-8" will always be supported as a character encoding, so I expect that UnsupportedEncodingException will never be thrown. But since UnsupportedEncodingException is checked, I must either catch it or declare it in the calling method's throws clause.
What I recommend in my talk is be sure and not simply swallow such exceptions, even though you think they will never happen, because someday they just might. Better to wrap them in a runtime exception that will result in a killed thread and a stack trace if they're ever actually thrown. I always put the comment, "// Should never happen", in such cases, and I programmed my IDE to generate such code by default when it generates catch clauses.
The feedback I got from the audience was that this is all well and good, but some would have wrapped the exception in an AssertionError instead of a plain old RuntimeException, because that is semantically more accurate. One reason I wrap it in RuntimeException is that in our web application, we have a last ditch catch clause that catches any uncaught Exceptions and prints out information to a log file that can be helpful in debugging. After printing the information, this last ditch catch clause exits normally (it doesn't rethrow any exception). Therefore, the app server knows nothing of an exception and happily and quietly returns the thread to its thread pool.
I want that information to be printed if a "should never happen" exception ever gets thrown. I could easily factor out the code that logs the information into a method called by two catch clauses, one for Exception and the other for AssertionError. Perhaps I should do that anyway in case some programmer we hire actually uses asserts, which Frank Sommers and I tend not to use. I don't catch Throwable, because in general Errors I figure I should let propagate out, allowing the app server to deal with them as it sees fit. Given that these exceptions really should never happen, I think the main concern should be how obvious is it to readers that a catch clause is a "should never happen" case. AssertionError may indicate that better than RuntimeException, but the comment "// Should never happen" I think makes it pretty clear.
What's your opinion? What exception would you wrap with in the "// Should never happen" case?
I suspect it depends on the use. In this case, if the UTF-8 isn't there, chances are it's not going to work next time around either, so having some form of *Error would make sense.
Then there's things that should be wrapped in IllegalStateException and IllegalArgumentException, which are special cases of the 'should never happen' brigade.
If nothing else fits, I use UnsupportedOperationException. It's pretty much a catch all and avoids direct instances of RuntimeException.
The downside of the AssertionError is that it presupposes 1.4; though since 1.3 is now EOL, maybe that's not as much of an issue as it used to be. Given that there's no other Error that makes sense (UnknownError perhaps) then a direct instance of Error may be useful sometimes.
I do the same thing for all checked exception. In you case I would create an exception ShouldNeverHappen that extends RuntimeException, then you can ditch the comment.
"An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch."
I'm not sure where to write the "should not happen", though I like Sven's idea of naming the exception
e.g.
try { String value = document.getText(0, document.getLength()); } catch (BadLocationException cannotHappen) { throw new Error(e1); }
But sometimes you need to explain why the exception cannot happen. For example, I have a class that takes a MessageDigest, Signature, and KeyPair in the constructor. And it tests that they work then, via
Later on, when it's actually processing real data,
try { signature.initSign(keyPair.getPrivate()); } catch (InvalidKeyException e) { // we already checked this signature in the constructor throw new Error(e); }
> Later on, when it's actually processing real data, > > try { > signature.initSign(keyPair.getPrivate()); > } > catch (InvalidKeyException e) { > // we already checked this signature in the > the constructor > throw new Error(e); > }
So you just crash the app? Wouldn't you want to log it or something? I'm not convinced that these are things no one should catch. These are things you handle in a fault barrier as described here:
> I do the same thing for all checked exception. In you case > I would create an exception ShouldNeverHappen > that extends RuntimeException, then you can ditch the > comment. > Well, since I never expect these exceptions, and therefore never want to catch them explicitly (just with a last-ditch catch clause), I don't think it is worth adding to the surface area of the design to create an exception class for them.
> Well, since I never expect these exceptions, and therefore > never want to catch them explicitly (just with a > last-ditch catch clause), I don't think it is worth adding > to the surface area of the design to create an exception > class for them.
I think the point was for documentation. I guess if you see a ShouldNotHappenException in the logs, you can look at your co-worker and say, "that shouldn't have happened."
Seriously though, it's possible to over think this. I don't see this as being any different from any other exception that isn't recoverable. Wrap it and make sure you have a fault-barrier. If you were wrong deal with it, otherwise don't waste time thinking about it. The point is that if it does happen, you don't lose the stack-trace and/or continue on in an inconsistent state. The only thing worse than a program that crashes is one where that doesn't when things are horribly wrong. I've spent enough time trying to fix problems after an application went ape-shit on a database.
> The feedback I got from the audience was that this is all > well and good, but some would have wrapped the exception > in an <code>AssertionError</code> instead of a plain old > <code>RuntimeException</code>, because that is > semantically more accurate.
OK, it just dawned on my why this is very wrong. Assertions should not be turned on in production. That's why it's fine that they extend Error: they will not be thrown.
Are people really making development decisions based on semantic arguments? AssertionError sounds more correct? Does anyone really consider that a valid argument?
> Assertions should not be turned on in production
This seems a very strange statement to me. Assertions make sure some invariant holds, why is it any less important that they hold in a released version than a debug version?
Turning off assertions is just like removing the seat belts from your car, just because you managed to drive to the shops once without dying. (I think that the gist of that quote comes from Tony Hoare, but I can't find the reference!).
> > Assertions should not be turned on in production > > This seems a very strange statement to me. Assertions > make sure some invariant holds, why is it any less > important that they hold in a released version than a > debug version?
Assertions are meant for finding programming errors. They are not meant to be used like runtime exceptions.
> Turning off assertions is just like removing the seat > belts from your car, just because you managed to drive to > the shops once without dying. (I think that the gist of > that quote comes from Tony Hoare, but I can't find the > reference!).
That's a pretty bad analogy. They are more like a trigger that causes the engine to shutdown when certain parameters are exceeded. Good for a test stand, not so good when you are driving on a high-speed road.
If they should not be turned off, why do you suppose there is an option to do so? Actually, the option is to turn them on as they are disabled by default. I use a much higher level of debugging in development than in production. Assertions in Java are not for testing input and the like.
If you want to check for something at runtime, you should be using Exceptions not assertions.
Here's a smattering of items I found with a simple google search:
"As it's highly likely that assertions won't be enabled during production runs (they're off by default), your program should not rely on assertions to execute correctly at runtime."
The author's use of the word 'must' is a little questionable here. Probably 'should' is meant.
"As a good programming practice, assert statements should not be used to check parameters of a public method. Also, Assertions must be disabled in production. Although you can, you must never attempt to catch an assertion error or any form of java.lang.Error."
> > Assertions should not be turned on in production
> This seems a very strange statement to me. Assertions make > sure some invariant holds, why is it any less important that > they hold in a released version than a debug version?
> Turning off assertions is just like removing the seat belts > from your car, just because you managed to drive to the > shops once without dying. (I think that the gist of that > quote comes from Tony Hoare, but I can't find the > reference!).
Bjarne Stroustrup compares it to wearing a life jacket in shallow water and taking it off before swimming in the ocean.
The concept comes from a concern with efficiency (whether that's speed, using too many resources, etc.) and a belief that enough testing will find cases where the assertion doesn't hold before the code is released.
On the other hand, I've seen more than a couple of released programs give me error messages of the kind "asserion failed on line XXX file YYY." That information would surely have been useful to a programmer with access to file YYY but to me it just looked shoddy.
If I ruled the world, I would keep *most* (but not all) assertions in running code, but change their behavior to launch a "report a bug with this app" window. I would also offer some incentive to find those bugs (coupon, $10 check, etc. for the first report). I know that would get expensive, but it would also be a great marketing gimmick, and may well pay for itself in increased sales.
> If I ruled the world, I would keep *most* (but not all) > assertions in running code, but change their behavior to > launch a "report a bug with this app" window. I would > also offer some incentive to find those bugs (coupon, $10 > check, etc. for the first report). I know that would get > expensive, but it would also be a great marketing gimmick, > and may well pay for itself in increased sales.
My intention is not to quibble over DBC. I don't use assertions because I don't find them to be very helpful in Java. For one, they can easily be turned off (i.e. by default.) I might find them more helpful in a language with more robust DBC features.
The point is that they were designed in Java to be used for testing. Using AssertionError for capturing runtime errors is a bad idea. If I turn off assertions, I should be able to expect to see no AssertionErrors.
> If I turn off assertions, I should > be able to expect to see no AssertionErrors.
Actually, that's not 100% correct, they can still be thrown during class initialization, if I understand correctly. But they should not be thrown from anything else.
So we should turn assertions off because: a) Google says so b) There is an option to do so :)
In my view, an assertion verifies a property so important that if violated the program can no longer carry on. For example, if I have an internal method in my software that should never ever (ever!) receive a null argument, I'd like to verify it with an assertion. This isn't a runtime exception, this is an error in the way I have designed my code. If I've turned assertions off, then the state of my program is effectively random, who knows what is going to happen? I would rather exit quickly in a known way, than hope that my "should never happen" event isn't going to cause the world to end. From "The Pragmatic Programmer", "dead programs tell no lies". As an example, if I'm writing a tree algorithm, I might make the assertion that each node has one parent. If this is violated, none of my tree algorithms will make any sense.
The car analogy definitely isn't perfect. The engine one you mention is better. Would you rather have an engine that shuts down quickly when something goes mechanically wrong, or would you rather cross your fingers and hope it doesn't explode? (I think I'll make that the last analogy I ever make here, I'm terrible at them!)
"The Pragmatic Programmer" by Andrew Hunt and Dave Thomas (excellent book btw!) advocates leaving assertions turned on at runtime. "Your first line of defense is checking for any possible error, and your second is using assertions to try to detect those you've missed"
Put another way, what harm does leaving assertions on do? The performance argument is a non-starter, as the majority of assertions are not performance intensive, and those that are can be made optional.
(I appreciate we're diverging from the main topic here, give nthat it was about checked exceptions in Java!).
Flat View: This topic has 73 replies
on 5 pages
[
12345
|
»
]