Checked exceptions I love you, but you have to go
googletesting.blogspot.com
googletesting.blogspot.com
I think it's really just a fundamental problem with the whole idea, and it's why any attempt to "fix" them will fail: the idea of checked exceptions is just deeply flawed.
If foo calls bar, something might go wrong, and foo should take some kind of action. If bar can't complete because of an IOException, it should throw it (or wrap it and throw the wrapper). Foo now knows that bar may not complete successfully, and can do what makes sense there (throw it's own exception, retry, etc). If foo can't complete because bar didn't complete, it should tell it's caller. If it matters that the reason Foo couldn't complete was an IOException, throw it, otherwise throw a more meaningful exception.
The only way to avoid that break of encapsulation is to catch the exception immediately in bar(), and then do something with it: either handle it, or rethrow it as something else, either a runtime exception or as a different checked exception. But that also isn't really ideal; in my experience, about 98% of the time even checked exceptions are throw-up-your-hands sort of programmer errors that you want to bounce a fair way up the stack to some more central error-handling location, or to kill the high-level operation being attempted. In other words . . . you generally just want to treat them exactly like runtime exceptions.
So while the theory of type-safety around checked exceptions is nice and all, in practice if you actually use them as part of type signatures they massively couple all the layers of your application, and I find them much more annoying than useful.
I think Java has ruined checked exceptions for the rest of us, because this article makes good points and successfully knocks down Java's exception system. I don't think this invalidates the concept of checking one's exceptions, though!
What would I do instead? Since it's always the prerogative of the receiver of a possible exception to rethrow it uncheckedly, then why not allow the type system to promote (/demote) a checked exception to unchecked at the catchpoint, without requiring an actual catch block? Some system like that could reduce the syntax clutter which is the root of the author's beef.
No type system support... but no catch block, either.
I would only recommend this as a last ditch effort to appease the Java compiler though, not an acceptable way to handle a common failure mode.
As a side note, does anyone else find the pattern (well, I would say headache) of dealing with checked exceptions similar to working with the IO monad in Haskell?
And yeah, monads have most of the same problems that checked exceptions do. Each action in the monad must have the same type; you can't just ignore one of those bits of extra information and declare that it doesn't matter in this context. For example, if your complicated algorithm writes to a log file, you probably don't care in the rest of the program and could just as easily treat it as pure. But the type system won't let you, unless you fall back on cheats like unsafePerformIO.
I dunno really what the right answer for this is, but I really like the Erlang philosophy toward errors. "Let it crash, then do something simpler." Instead of trying to enumerate all the ways your program can fail, it just assumes that you will fail sometimes, so you ought to try multiple ways to succeed instead. That requires quite a paradigm shift from the way programmers normally think about programming, though.
http://caml.inria.fr/pub/old_caml_site/ocamlexc/ocamlexc.htm
"Ocamlexc is a framework designed to statically analyze Objective Caml programs in order to discover potentially raised and uncaught exceptions. Such exceptions are harmful because they cause the immediate end of the running program. This tool can hence be seen as a static debugging tools, adding more safety to the already powerful static and strong typing system that makes ML programs so robust."
Checked exceptions ruins that advantage of exceptions -- you're back to writing a whole bunch of buggy error handling code rather than just a few key catches. The result is errors are being hidden, masked, or ignored for absolutely no gain except to satisfy the compiler.
The .NET pattern of inner exceptions is nice too (relevant to the article's example, you could throw an NHibernateException(inner exception:SQLForeignKeyViolatedException)).
It's nice I guess from a certainty and stability standpoint in Java to know that you won't have an exception crash your system, but even then you aren't going to be sure because some exceptions do crash your system because they aren't checked (e.g. null pointer, array index etc.).
In my opinion Java is a dead language anyway. The language's bloat (exceesive boiler-plate required for everything), lack of high-level functionality and general approach to boxing in the programmer mean that new programmers don't want to use it (most will learn it though).
The slow initialisation time (JVM problem) and lack of native interfaces (despite the work done here) mean that companies don't want to use it for customer products.
For internal apps, I'd wager that the company just wants something that most people know and that is quick to develop in, and while Java has some ground here I think other languages will be making strong headway too, especially when you have some control on the deployment platforms.
Java just strikes me as dissapointing now. It is probably single-handedly responsible for us getting over the fear of automatic memory management and GC. Similarly it's had massive influences on virtual machines and easy cross-platform deployment. Just about every CS student in the world knows Java. But right now it has failed to innovate with the resurgent popularity for language functionality, address the issue of bloat or develop on the issues that discourage people actually using it for cross-platform deployment.
In the mobile sector it's pretty strong, but Objective-C/iPhone will probably hurt that, and it's only strong because of the JVM's portability. On the web it had the potential to take out flash, but the incredible load time and associated lag of the JVM initialising has killed that chance.
Overall, Java is only afloat because it is too big to sink.
No. If you can't remember what it throws, you can't remember the documentation. If you can't remember the documentation, you don't fully know how to use it properly. Go read the documentation; IDEs are a crutch.
EDIT: I'm completely serious. http://docs.python.org/library/ and help() are my best friends, in that order.
And I didn't say you can't check the domentation from the IDE (through a nice context link) but I still think mouseover on a method that lists exceptions (as Visual Studio does) is the ideal solution as it gives me the information I need as I code.
NB: VS exception info is comment documentation based, I have no idea why the compiler doesn't generate this information as much as possible becuase then you are getting some of the advantage of checked exceptions without the cost.
As a counterpoint to knowing the documentation, consider the System.Reflection.MethodBase.Invoke method in .NET which I have in front of me, are you going to remember all these exceptions:
// Exceptions:
// System.Reflection.TargetException:
// The obj parameter is null and the method is not static. -or- The method
// is not declared or inherited by the class of obj. -or- A static constructor
// is invoked, and obj is neither null nor an instance of the class that declared
// the constructor.
//
// System.ArgumentException:
// The elements of the parameters array do not match the signature of the method
// or constructor reflected by this instance.
//
// System.Reflection.TargetInvocationException:
// The invoked method or constructor throws an exception.
//
// System.Reflection.TargetParameterCountException:
// The parameters array does not have the correct number of arguments.
//
// System.MethodAccessException:
// The caller does not have permission to execute the constructor.
//
// System.InvalidOperationException:
// The type that declares the method is an open generic type. That is, the System.Type.ContainsGenericParameters
// property returns true for the declaring type.Yeah and you just get a list of possible exceptions rather than a description of each which is a fair point to make too. Maybe it's configurable though.
Java the virtual machine is alive and well and I suspect will have a long life.
In that way, it makes sense for a top-level handler, such as at the main() routine or in the event loop in a GUI app, to be the one to handle it, and for all intermediates to pass it up. The fact that most meaningful applications do I/O at some level, means that almost the only routines that can be indicated not to throw this exception or a similar I/O exception, are functionally pure ones, or the ones that implement the aforementioned user notification.
That's not seeing the forest for the trees. Unless a specific inner loop of the program shows up in a profiler as the hotspot because of an exception, this just isn't something you should ever worry about in 99% of code. Don't throw out the nice abstractions that make code simple unless you know for sure it's the actual problem, rarely is that the case for throwing exceptions. In this particular instance, I'd say you're just wrong about not using an exception.
Some parts of Java's API have made poor decisions in their use of checked exceptions (the close methods on file input streams and database connections, for example), but that doesn't invalidate the concept.
Correct use of checked exceptions helps create more solid code with less testing required, because the compiler is able to do checks that would otherwise have to be written into unit tests. Incorrect use of checked exceptions is what leads to all of the objections I've seen listed here.
You answered your own question. Inappropriate use of checked exceptions is built into the heart of the Java standard libraries, which means that (a) every new Java programmer is taught, consciously or subconsciously, to use them everywhere, at least until the programmer is very explicitly educated about their badness; (b) even experienced Java programmers must deal with them every day, and 95% of the checked exceptions they deal with are an unredeemed pain in the ass, so before long the very sight of one makes you flinch. It's Pavlovian.
In a language community where checked exceptions were a completely optional add-on which was only used when appropriate, they might have a much better reputation.
try { foo.bar(); } catch (FooException fe) { logger.error(fe); }
A descriptive crash would be more useful, especially if the exception is thrown as a result of an invariant being violated. Scala is a step forwards in this manner, but now there's the issue of remembering which Java methods (foreign to Scala) rely on exceptions to convey important information (e.g. anything which throws InterruptedException).
try { foo.bar(); } catch (Exception ex) { Logger.getLogger(InvalidConversionException.class.getName()).log(Level.SEVERE, null, ex); }
Two are unchecked RuntimeException extensions to indicate operating environment issues, and, implementation issues (aka bugs).
Finally, if the api semantics seem to indicate it, api level checked exceptions indicating misuse of the api (aka user errors). Typical example are cases where the api semantics require return values which preclude uniform application of an 'error code' as a viable means of alerting user error. I don't believe it is a good practice to throw an unchecked exception in these cases.
Both checked and unchecked exceptions have their uses.