Personally, I don't like checked exceptions. But why? And can we do anything about it?
Checked exceptions
Its fairly well known that checked exceptions were a kind of experiment in Java. Its also fairly well known that other newer languages are not choosing to follow. The basic reason is that as a language feature they haven't met their goal.
The expectation was that checked exceptions would improve exception handling quality. The reality is that they haven't:
public void process() { try { callSomeExceptionThrowingMethod(); } catch (Exception ex) { // ignore } }
I hope that most of us recognise this as an anti-pattern (in most cases). Rather than discuss this much longer, I'll point everyone at Joshua Gertzen's blog.
His blog reminded me of a possible library change (yes library, not language!) I'd thought of that might help. At least it is something I'd like opinions on:
public void process() { try { callSomeExceptionThrowingMethod(); } catch (Exception ex) { ex.rethrowUnchecked(); } }
So, what does 'rethrowUnchecked()' on Exception do? Well it would rethrow the exception, but ignoring the checked exception status of the exception.
public void rethrowUnchecked() { Unsafe.getUnsafe().throwException(this); return null; }
This all works with Java today. There is no language change, just an alternative view of an existing capability.
So, why would this be useful? Well, I suggest that this could be a better way to handle annoying checked exceptions that we don't really care about. In particular, I believe that it would be easier to understand the exception trace, as it wouldn't consist of lots of nested exceptions - no more 'throw new RuntimeException(ex)'.
Summary
I'm not convinced of the benefits of this one yet. It seems neat, but does it really benefit us, as we still have to write the catch block? Perhaps it is more suited to a language change? Opinions welcome as always :-)
I find that checked exceptions are one of the strengths of Java since they lead to writing more robust code. :-) Yes, the one that you mentioned is an anti-pattern (in all cases), but I don't understand how not having checked exceptions and people happily ignoring that some piece of code can fail is a better thing. To me checked exceptions did meet their goal, and I don't see how pointing out a bad habit could demonstrate the opposite: I don't see any language that can't be used in a poor way by undisciplined people.
ReplyDeleteThe improvement of your suggestion are marginal IMHO, just having a tidier stack trace, but I don't see the world changing for that.
Checked and unchecked exceptions both have their places.
ReplyDeleteMy view is, for error conditions from which the program can recover, checked exceptions are a great way to carry the information back in the call stack. You can carry the information with unchecked exceptions too, but you will notice that the users of your code will often miss catching them and the exceptions will end up in a global exception handler.
Java's checked exceptions would be fine if exception handling was first class. In other words, if you could pass an exception handler in as a parameter (or have it be part of some state somewhere) and have that 'be' the catch block for that method, then you wouldn't have to decide everywhere whether to catch, rethrow or specify.
ReplyDeleteScala doesn't have this built-in, but I added it in a few lines of code, that if javapolis is anything to go by, would scare the pants off Josh Bloch. (Actually Scala doesn't have checked exceptions so implementing this as a user is much easier than it would be in BGGA .. one less type variable).
Anyway, if at least half of Java programmers are worse than average, the change you describe will lead many of them to catch Exception everywhere (instead of RuntimeException) because it could have been rethrown using this mechanism.
My feelings with checked exceptions is that
ReplyDeletethey are necessary for certain type of applcations, but they should be used minimally in the core libraries. instead, the power of checked exceptions should be left to the user. Unfortunately they are used in the core libraries extensively, and wrongly. (IO, Reflection, JDBC, URI etc.).
Another, maybe an evil idea would be using sort of an annotation or a new keyword to hint compiler to compile silently if a method is not handling the checked exception. So that if user is really disturbed by it, he can suppress it for the method, or class etc.
Primarily i suggest you to read the next seminal piece about "Contigencies vs Failures":
ReplyDeletehttp://dev2dev.bea.com/pub/a/2006/11/effective-exceptions.html
In a nutshell the article says that the Contigencies(checked) of one layer are the Failures(unchecked) for the layers above, and vice-verse.
So, use and wrap one into the other with responsbility but with a clear architectural aspect.
Please, don't discredit checked-exceptions due to the problems you see today when using them, for things would be quite the opposite if there weren't invented by Goshling.
This thing indeed happens with C# where frequently exceptions end-up where they shouldn't.
Even the designer of C# cannot make a good-enough statement against checked-exceptions:
http://www.artima.com/intv/handcuffs.html
Event today, i still forget sometimes to handle the (unchecked) java.util.regex.PatternSyntaxException...
Finally, please have a look at the modarate and fair article about this java-old dilema:
http://colmsmyth.blogspot.com/2007/06/evolving-java-increasing-demand-to.html
Why not to add the ExceptionsHandler using annotation, so the checked exception would be handle by this special class? ... or add a new keyword for method declaration, like
ReplyDelete@ExceptionHandler(Handler.class)
public void foo() throws Exception {
// some buggy code here
}
OR
public void foo() throws Exception handledBy ExceptionHandler {
// some buggy code here
}
... there might be several unchecked exceptions thrown by the same method, but we still could implement handlers in some elegant way.
Unfortunately, once you've done this you can't catch the exception! The Java programming language won't let you write a catch clause for a checked exception type that it believes can't be thrown from the try block.
ReplyDeleteThe suggested solution by Joshua Gertzen contains this line:
ReplyDeleteif (ex instanceof RuntimeException)
throw (RuntimeException) ex;
The above line is itself an anti-pattern, since it destroys the original stack-trace.
The same applies for the reflection trick.
The problem becomes increasingly serious as the try-catch-surounded code gets bigger.
Eventually, the bargain is between a nested stack-trace and a false one.
> throw (RuntimeException) ex;
ReplyDelete> The above line is itself an anti-pattern, since it
> destroys the original stack-trace.
Not true, aka false: the stack trace is gathered during exception allocation, not during throw, so it is preserved.
Neal is right; handling such exceptions would require an ugly catch (Exception e) block with an instanceof chain or similar mechanism.
ReplyDeleteI could not disagree with you more - checked exceptions are one of my favorite features of the Java language, and their omission is one of the biggest weaknesses of weakly-typed languages. Checked exceptions allow you to have multiple exit points from your library code, knowing that all of them will be handled in some way by the calling code. This is a critically important ability.
ReplyDeleteThere is an easier way to throw unchecked exception without using Unsafe:
ReplyDelete===
@SuppressWarnings({"unchecked"})
private static void throw0(Throwable e) throws E {
throw (E) e;
}
public static void throwException(Throwable e) {
A.throw0(e);
}
===
I agreed, that checked exceptions are evil.
The effect of "rethrowUnchecked" could be achieved by a utility exception class I have been using for a while now - UniversalRuntimeException (click on my name below for a link).
ReplyDeleteIn addition to unwrapping any tedious wrapping exceptions (including any other instances of itself) it guarantees that a single copy of the deepest stack trace will be preserved and provides a convenient location to add an informative extra detail message.
I always love how checked exceptions seem to cause flame wars. The quote from Anders Hejlsberg (linked above) I liked was "You see programmers picking up new APIs that have all these throws clauses, and then you see how convoluted their code gets, and you realize the checked exceptions aren't helping them any. It is sort of these dictatorial API designers telling you how to do your exception handling. They should not be doing that.
ReplyDeleteIn other words, I understand the difference in concept between recoverable and non-recoverable exceptions. The problem is that in practice, its only the caller of an API that can know if it is recoverable or not. Thus, any API that throws a checked exception is really having a huge ego about how it should be handled.
I am also amused by the variety of different ways that everyone is using to get around checked exceptions. I think the generics one is especially amusing!
@Neal, Michael, Thanks, and yes I agree now that the exception could not then be caught using standard catch blocks. Unfortunately, this probably means that this concept really isn't useful enough to go with.
Fortunately it is very easy to stop a compiler from complaining about checked exceptions.
ReplyDeleteHere’s a guide for the Eclipse compiler:
- From within Eclipse choose „File/Import/Plug-ins and Fragments”.
- In the next dialog select "Import as" "Projects with source folder".
- In the next dialog select "org.eclipse.jdt.core".
- Open the class “ProblemReporter.java”
- Add this code to the “unhandledException()” method:
// make it customizable thru a system property
private static final boolean _ignoreUnhandledException = System.getProperty("ignore.unhandled.exception", null) != null;
public void unhandledException(TypeBinding exceptionType, ASTNode location) {
if (_ignoreUnhandledException) {
return;
}
...
}
- Exit Eclipse.
- Put the compiled "ProblemReporter.class" into /plugins/org.eclipse.jdt.core.[version].jar, overwriting the already existing class.
- Start Eclipse with -vmargs -Dignore.unhandled.exception
- This code compiles fine:
public class Q {
public static void main(String[] args) {
String helloWorld = (String)Class.forName(String.class.getName()).getConstructor(String.class).newInstance("hello world");
System.out.println(helloWorld);
}
}
This brings a totally new java programming feeling.
I assume u guys are experienced programmers (like mine ;) and know how to deal with such a feature.
OpenJDK is easy as well. Tell me if would like to know how.
Although I agree with you about the anti-pattern problem somehow, checked exceptions, at least for me, do the following:
ReplyDelete- While coding in java I can see exactly what kinds of errors are possible (nothing I can't gather by looking at docs or having a little imagination), but at least I'm forced right there and then to think about error conditions. This, usually leads to ignoring most of them, but at least the language inherently brings that kind of thought process upon me with force.
- While coding in, say, ruby, I have none of the above, and it really bothers me that I'm not really sure what kind of errors a certain call is likely to encounter, and this information is really hard to find coz its encapsulated in the code of the library itself and not even in method signatures.
"It is sort of these dictatorial API designers telling you how to do your exception handling. "
ReplyDeleteI don't see it more or less dictatorial than deciding what are the type of the arguments of a method, or that a certain feature is implemented in one, two or three method calls, etc: these are all things that put constraints in the code that uses the API. If you don't like them, don't use that API, choose another or write your own (after thinking ten times, of course). Checked exceptions, in other words, are just part of the contract. Which, of course, brings us back to a design issue, not to the language features stuff, and of course checked exceptions can be misused in a bad design. I don't agree with the vision that checked exceptions shouldn't be used in a low level library: e.g. if you open a file, FileNotFoundException must be checked since the non-existence of that file is part of the logical post-conditions of the operation. Conversely, I agree that e.g. a SQLException because of a syntax error in the SQL should be non checked, as it's a programming error such as NPE or DivideByZero.
Checked exceptions are fine for domain specific uses (InsufficientFundsException, InvalidDosageException, etc)...
ReplyDeleteThe problem most people have is because Sun mistakenly decided to use checked exceptions within the core API. That was the mistake.
What Sun needs to do is simply move SQLException and IOException to RuntimeExceptions where they belong.
We should not have to 'check' these and that would solve 98.765% of the problems of checked exceptions.
ignoring an exception may be an anti-pattern in code, but you had to think about it before doing it, so on another level the pattern did do it's job. Perhaps it's better to add the reason why you can ignore it to your command, so the thinking-process the pattern pushed you into is not lost.
ReplyDeleteMaybe an @ignoreException(reason="String") would be cool?
krizzdewizz: Thanks for the eclipse code. It would be nice to get this into Kijaro (OpenJDK changes) at some point.
ReplyDeleteFabrizio/Dan: Your two posts illustrate the whole checked exception mess. Fabrizio argues for FileNotFoundException to be checked (because a file might not be there), while Dan argues that all IOExceptions (including FileNotFoundException) shoudl be runtime.
The problem is that whether an exception is something that the caller should check or not is generally up to the context of the caller. As such, any API declaring checked exceptions is being very dictatorial to its users.