
Checked exceptions I love you, but you have to go - fogus
http://googletesting.blogspot.com/2009/09/checked-exceptions-i-love-you-but-you.html
======
akeefer
To me one of the fundamental issues with checked exceptions is that they break
encapsulation. There's no way around it: if foo calls bar, and bar calls
readFile which throws an IOException, assuming bar is unable to handle the
exception itself (which is generally the case) and you want it to be reported
up the stack (say, all the way to the web request handler), you have two
options: you declare every method in the chain as throwing an IOException,
thus polluting a ton of higher-level code with information that should be
restricted to a lower layer, or you catch it and wrap it in a runtime
exception, defeating the purpose of having that be a checked exception.

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.

~~~
efsavage
The checked exception didn't break encapsulation here, you did. You have alot
more than two options, and the two you listed aren't very good ones.

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.

~~~
akeefer
Let me try to phrase the argument more clearly: if you want to pass on a
checked exception via redeclaration in the "throws" clause, you've broken
encapsulation because a change to the lower layer implies changes all the way
up the stack. If bar() was originally calling readDatabase() that threw a
SQLException, and I change it to call readFile() that throws an IOException,
if I'm passing that exception up the stack I have to change bar's signature
purely due to an implementation change, and so on up the stack. So a change at
the lower layer has now forced me to make changes all the way through my
application stack. Henceforth, encapsulation is broken by what should just be
an implementation change.

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.

------
lincolnq
Fundamentally I want to be able to ask my programming language "what
exceptions might propagate to here?" Having this ability allows me to make
stronger claims that my program is correct, because then I can say that the
only exceptions which can propagate to that point are of a type I have decided
not to handle (like the filesystem being disconnected) and this can be a
strong safety property.

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.

~~~
cmars232
You could use RuntimeException as a superclass for your exceptions, or wrap
checked exceptions in a RuntimeException. I'll often rethrow exceptions this
way when I have to deal with something horribly wrong (like I/O or UI
meltdown, etc.) in a place where I have to deal with the checked exception..
This is handled gracefully in the Eclipse workbench as a popup though, YMMV.

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?

~~~
nostrademons
I often explain monads to laypeople as "It's a way to abstract away extra
information that's passed through the computation, and define arbitrary ways
to handle that information." One of the possible types of "extra information"
that may be attached are the types of exceptions thrown: see the Error monad.

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.

------
wvenable
The difference between error codes and exceptions are that, for error codes,
you must check the result of every function call and method and in some way
handle that result. Contrast this to exceptions, where the advantage is that
your error handling is centralized. You should throw as much as necessary and
catch in a few key places.

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.

------
nopassrecover
Relying on the IDE to know which exceptions can be thrown is nicer I think.

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.

~~~
swolchok
_Relying on the IDE to know which exceptions can be thrown is nicer I think._

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.

~~~
nopassrecover
I think knowing every exception a method can throw and knowing the method are
different things. I want to be able to write code, while I'm in the zone and
thinking about the business problem, not have to jump and navigate a web site
for every method call.

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.

~~~
swolchok
I didn't say you have to _know_ the documentation, and I'll admit I'm behind
on how much of it IDEs show you. In my recollection, you generally get a list
of language-level constructs and that's it. For example, the names of those
exceptions are not as useful as the text you've shown there. If VS does that
for exceptions, great! Contrast it with the 2003/2005 IntelliSense feature,
where you just get method prototypes.

~~~
nopassrecover
I misinterpreted "No. If you can't remember what it throws, you can't remember
the documentation" as _know_ the documentation but I can see your point now.

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.

------
barrkel
FileNotFoundException is not really a corner case, it's all but unavoidable
race. No matter how soon you open the file after verifying its existence, it
could have gone away. And the only reasonable thing you can do in the face of
it is route the message that the file is missing to the user one way or
another, and possibly exit.

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.

~~~
gnaritas
Why would you verify it's existence? Just open it, you either get it or you
don't. If you don't then catch the exception and do what you would have done
if you'd have checked and it wasn't there. Honest question?

~~~
mkinsella
Opening a file (or attempting to) is resource intensive and throwing/catching
exceptions is sloooow.

~~~
swolchok
Both opening the file and checking whether it exists involve a syscall, which
dwarfs the overhead of throwing and catching an exception. If you check
whether it exists and then try to open it, that's _two_ syscalls.

~~~
swolchok
On reflection, it occurs to me that a Sufficiently Smart Compiler (TM) could
figure out that you were going to open the file right after checking whether
it exists and just call open(2) as the existence check instead of stat(2) and
then open(2). This seems to depend on the details of the library
implementation as well, though.

------
vilya
Why does everyone seem to think this a black-and-white issue? Checked
exceptions are appropriate for some things, unchecked exceptions are
appropriate for others. Use the right tool for the job.

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.

~~~
mechanical_fish
_Why does everyone seem to think this a black-and-white issue?_

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.

------
strlen
Checked exceptions are probably are of my biggest pet-peeves about Java
(erasure and lack of closures/first order functions are the other ones). They
create excess verbosity, but what good are they if most code I've seen does
this:

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).

~~~
spectre
Most try-catches are considered boiler plate and are often generated. For
example of the default options in NetBeans generates the following:

try { foo.bar(); } catch (Exception ex) {
Logger.getLogger(InvalidConversionException.class.getName()).log(Level.SEVERE,
null, ex); }

------
JulianMorrison
FWIW, Scala lets you call java code that would throw checked exceptions - and
not check them. The checking is only enforced at compile time by javac.

------
JulianMorrison
The most important problem with checked exceptions in Java is the way they
interact with inheritance. If you could just declare "throws" everywhere, you
could at least live up to the ideal of knowing the exceptions to expect. But
you can't override and add a new "throws". Substitution principle, yeah, I
know. But why did they design Runnable without "throws Exception"?

~~~
vilya
Runnables don't throw checked exceptions for the same reason that main()
doesn't - because there's nothing sensible that could catch it.

~~~
JulianMorrison
You can declare main() as "throws Exception".

------
lucifer
I typically use 3 categories of exceptions when building frameworks or
libraries.

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.

