14

Java's checked exceptions have gotten some bad press over the years. A telling sign is that it's literally the only language in the world that has them (not even other JVM languages like Groovy and Scala). Prominent Java libraries like Spring and Hibernate also don't use them.

I personally have found one use for them (in business logic between layers), but otherwise I'm pretty anti-checked exceptions.

Are there any other uses that I don't realize?

2
  • All Java core libraries use checked exceptions quite extensively. Commented Nov 16, 2010 at 7:40
  • 3
    @Joonas I know, and it's a pain!
    – Brad Cupit
    Commented Nov 16, 2010 at 12:59

8 Answers 8

25

First of all, like any other programming paradigm you need to do it right for it to work well.

For me the advantage of checked exceptions is that the authors of the Java runtime library ALREADY have decided for me what common problems I might reasonably be expected to be able to handle at the calling point (as opposed to a top-level catch-print-die block) and consider as early as possible how to handle these problems.

I like checked exceptions because they make my code more robust by forcing me to think about error recovery as early as possible.

To be more precise, to me this makes my code more robust as it forces me to consider strange corner cases very early in the process as opposed to saying "Oops, my code does not handle if the file doesn't exist yet" based on an error in production, which you then have to rework your code to handle. Adding error handling to existing code can be a non-trivial task - and hence expensive - when reaching maintenance as opposed to just doing it right from the start.

It might be that the missing file is a fatal thing and should cause the program to crash in flames, but then you make that decision with

} catch (FileNotFoundException e) {
  throw new RuntimeException("Important file not present", e);
}

This also shows a very important side effect. If you wrap an exception, you can add an explanation which goes in the stack-trace! This is so extremely powerful because you can add information about e.g. the name of the file that was missing, or the parameters passed to this method or other diagnostic information, and that information is present right in the stack trace which frequently is the single thing you get when a program has crashed.

People may say "we can just run this in the debugger to reproduce", but I have found that very frequently production errors cannot be reproduced later, and we cannot run debuggers in production except for very nasty cases where essentially your job is at stake.

The more information in your stack trace, the better. Checked exceptions help me get that information in there, and early.


EDIT: This goes for library designers as well. One library I use on a daily basis contains many, many checked exceptions which could have been designed much better making it less tedious to use.

3
  • +1. Spring's designers did a good job of translating a lot of the Hibernate exceptions into unchecked exceptions.
    – Fil
    Commented Nov 18, 2010 at 20:31
  • FYI: Frank Sommers mentioned in this thread that fault-tolerant software often rely on the very same mechanism. Perhaps you can subdivide your answer into the recoverable case and the fatal case.
    – rwong
    Commented May 14, 2011 at 10:25
  • @rwong, could you please explain in more detail what you have in mind`?
    – user1249
    Commented May 16, 2011 at 9:37
13

You've got two good answers which explain what checked exceptions have become in practice. (+1 to both.) But it would also be worthwhile to examine what they were intended for in theory, because the intention is actually worthwhile.

Checked exceptions are actually intended to make the language more type safe. Consider a simple method like integer multiplication. You might think that the result type of this method would be an integer, but, strictly speaking, the result is either an integer or an overflow exception. Considering the integer result by itself as the return type of the method does not express the full range of the function.

Seen in this light, it's not strictly true to say that checked exceptions have not found their way into other languages. They have just not taken the form that Java used. In Haskell applications, it is common to use algebraic data types to distinguish between successful and unsuccessful completion of the function. Although this is not an exception, per se, the intention is very much the same as a checked exception; it is an API designed to force the API consumer to handle both the successful in the unsuccessful case, e.g.:

data Foo a =
     Success a
   | DidNotWorkBecauseOfA
   | DidNotWorkBecauseOfB

This tells the programmer that the function has two additional possible results besides success.

1
  • +1 for checked exceptions being about type safety. I've never heard that idea before, but it makes so much sense.
    – Ixrec
    Commented Feb 15, 2015 at 13:43
12

IMO, checked exceptions are a flawed implementation of what might have been a pretty decent idea (under completely different circumstances -- but really isn't even a good idea under the current circumstance).

The good idea is that it would be nice to have the compiler verify that all exceptions that a program has a potential to throw will be caught. The flawed implementation is that to do that, Java forces you to deal with the exception directly in whatever class invokes anything that's declared to throw a checked exception. One of the most basic ideas (and advantages) of exception handling is that in case of an error, it allows intermediate layers of code that have nothing to do with a particular error, to completely ignore its very existence. Checked exceptions (as implemented in Java) don't allow that, thus destroying a major (the primary?) advantage of exception handling to start with.

In theory, they could have made checked exceptions useful by enforcing them only on a program-wide basis -- i.e., while "building" the program, build a tree of all the control paths in the program. Various nodes in the tree would be annotated with 1) exceptions they can generate, and 2) exceptions they can catch. To assure the program was correct, you'd then walk the tree, verifying that every exception that was thrown at any level in the tree was caught at some higher level in the tree.

The reason they didn't do that (I'd guess, anyway) is that doing so would be excruciatingly difficult -- in fact, I doubt anybody's written a build system that can do that for anything but extremely simple (bordering on "toy") languages/systems. For Java, things like dynamic class loading render it even more difficult than in many other cases. Worse, (unlike something like C) Java isn't (at least normally) statically compiled/linked to an executable. That means nothing in the system really has the global awareness to even try to do this kind of enforcement until the end user actually starts to load the program to run it.

Doing enforcement at that point is impractical for a couple of reasons. First of all, even at best it would extend startup times, which are already one of the single biggest, most common complaints about Java. Second, to do much good, you really need to detect the problem early enough for a programmer to fix it. When the user is loading the program, it's too late to do much good -- your only choices at that point are to ignore the problem, or refuse to load/run the program at all, on the off chance that there might be an exception that wasn't caught.

As they are, checked exceptions are worse than useless, but alternative designs for checked exceptions are even worse. While the basic idea for checked exceptions seems like a good one, it's really not very good, and happens to be a particularly poor fit for Java. For something like C++, that's normally compiled/linked into a complete executable with nothing much like reflection/dynamic class loading, you'd stand a little more chance (though, quite frankly, even then enforcing them correctly without the same kind of mess they currently cause in Java would still probably be beyond the current state of the art).

4
  • Your very first initial statement about having to handle the exception directly is already false; you can simply add a throws statement, and that throws statement may be of a parent type. Furthermore, if you really don't think you have to handle it you can simply convert it to a RuntimeException instead. IDE's commonly help you with both tasks. Commented Apr 26, 2014 at 10:32
  • 3
    @owlstead: Thanks--I probably should have been more careful with the wording there. The point wasn't so much that you actually had to catch the exception as it was that every intermediate level of code needs to be aware of every exception that might flow through it. As for the rest: having a tool that makes it quick and easy to make a mess of your code doesn't change the fact that it's making a mess of the code. Commented Apr 26, 2014 at 17:30
  • Checked exceptions were intended for contingencies -- predictable & recoverable outcomes other than success, as distinct from failures -- unpredictable low-level/ or system problems. FileNotFound or error opening a JDBC connection were both correctly considered contingencies. Unfortunately, Java library designers made a total mistake & assigned all other IO and SQL exceptions to the 'checked' class also; despite these being almost completely unrecoverable. literatejava.com/exceptions/…
    – Thomas W
    Commented Jun 2, 2014 at 9:47
  • @owlstead: Checked exceptions should only bubble through intermediate layers of the call stack if they are thrown in cases that the intermediate calling code expects. IMHO, checked exceptions would have been a good thing if callers had to either catch them or indicate whether or not they were expected; unexpected exceptions should be automatically wrapped in an UnexpectedException type derived from RuntimeException. Note that "throws" and "doesn't expect" are not contradictory; if foo throws BozException and calls bar, that doesn't mean it expects bar to throw BozException.
    – supercat
    Commented Jul 9, 2014 at 20:59
11

They're really good for annoying programmers and encouraging exception swallowing. Half the point of exceptions is so that you have a sane default way of handling errors and don't have to think about explicitly propagating error conditions you can't handle. (The sane default being that if you never handle the error anywhere in your code, you've effectively asserted that it can't happen, and are left with a sane exit and a stack trace if you're wrong.) Checked exceptions defeat this. They feel a lot like having to explicitly propagate errors in C.

1
  • 4
    Easy fix: throws FileNotFoundException. Hard fix: catch (FileNotFoundException e) { throw RuntimeException(e); } Commented Oct 9, 2012 at 18:39
6

I think it is fair to say that checked exceptions were a bit of a failed experiment. Where they went wrong is that they broke layering:

  • Module A might be built on top of Module B, where
  • Module B might be built on top of Module C.
  • Module C might know how to identify an error, and
  • Module A might know how to handle the error.

The nice separation of concerned is broken, because now knowledge of errors that could have been limited to A and C now have to be scattered over B.

There is a nice discussion of checked exceptions on Wikipedia.

And Bruce Eckel has a nice article on it as well. Here's a quote:

[T]he more random rules you pile onto the programmer, rules that have nothing to do with solving the problem at hand, the slower the programmer can produce. And this does not appear to be a linear factor, but an exponential one

I believe for the case of C++, if all methods have the throws specification clause, then you can have some nice optimizations. I don't believe Java could have those advantages anyway, though, because RuntimeExceptions aren't checked. A modern JIT should be able to optimize the code just fine anyway.

One nice feature of AspectJ is exception softening: You can turn checked exceptions into unchecked exceptions, specifically to enhance layering.

Perhaps it's ironic that Java went through all of this trouble, when it could have checked for null instead, which might have been much more valuable.

2
  • haha, never thought about that checking for null thing as a decision they didn't make... But I finally understood that it's NOT an innate problem after working in Objective-C, which allows nulls to have methods called. Commented Nov 16, 2010 at 4:23
  • 3
    null-checking is a much greater pain - you ALWAYS have to check - plus it does not tell the reason why, which a well-named exception does.
    – user1249
    Commented Nov 16, 2010 at 4:41
6

I love exceptions.

I am, however, constantly bemused by their miss-use.

  1. Don't use them for flow-handling. You don't want code that tries to do something and uses an exception as a trigger to do something else instead because Exceptions are objects that need to be created and use memory etc. etc. just because you couldn't be bothered to write some kind of if() check before you made your call. That's just lazy and gives the glorious Exception a bad name.

  2. Don't swallow them. Ever. Under any circumstances. As an absolute minimum you stick something in your log file to indicate that an Exception happened. Trying to track your way through code that swallows exceptions is a nightmare. Again, curse you exception-swallowers for bringing the mighty Exception into disrepute!

  3. Do treat Exceptions with your OO hat on. Create your own Exception objects with meaningful hierarchies. Layer your business logic and your exceptions hand in hand. I used to find that if I started on a new area of a system I'd find the need to sub-class Exception within half an hour of coding so these days I start by writing the Exception classes.

  4. If you're writing 'frameworky' bits of code, make sure all your initial interfaces are written to throw your own new Exceptions where appropriate... and make sure your coders have some sample code around the place of what to do when their code throws an IOException but the interface they're writing to wants to throw a 'ReportingApplicationException'.

Once you've groked how to make Exceptions work for you you'll never look back.

3
  • 2
    +1 for good instructions. Also, where appropriate, use initCause or initialize the exception with the exception that caused it. Example: You have an I/O utility that you only need an exception if the write fails. However, there are multiple reasons that a write could fail (couldn't get access, write error, etc.) Throw your custom exception with the cause one so that the original problem is not swallowed.
    – Michael K
    Commented Nov 18, 2010 at 16:54
  • 3
    I don't want to be rude but what does this have to do with CHECKED exceptions? :)
    – palto
    Commented Jun 12, 2012 at 13:54
  • Could be rewritten to write your own hierarchy of checked exceptions. Commented Apr 26, 2014 at 10:35
5

Checked exceptions should have encouraged people to handle errors close to there source. The further away from the source, the more functions have terminated in the middle of running, and the more likely that the system has entered an inconsistent state. Additionally, it is more likely that you catch the wrong exception by accident.

Sadly, people have tended to either ignore exceptions or add ever increasing throw specifications. Both of these miss the point of what checked exceptions are suppose to encourage. They are like transforming procedural code to use many Getter and Setter functions supposedly making it OO.

Essentially, checked exceptions are attempting to prove a certain degree of correctness in your code. Its pretty much the same idea as static typing, in that it attempts to prove that certain things are correct before the code even runs. The problem is that all of that extra proof takes effort and is the effort worthwhile?

7
  • 2
    "Ignoring exceptions" is often correct -- many times the best response to an exception is to let the app crash. For a theoretical basis for this point of view, read Bertrand Meyer's Object Oriented Software Construction. He shows that if exceptions are used properly (for contract violations) that there are essentially two correct responses: (1) let the app crash or (2) fix the problem which caused the exception and restart the process. Read Meyer for details; it's hard to summarize in a comment. Commented Nov 16, 2010 at 13:40
  • 1
    @Craig Stuntz, by ignoring exceptions I meant swallowing them. Commented Nov 16, 2010 at 14:17
  • Ah, that is different. I agree you should not swallow them. Commented Nov 16, 2010 at 15:30
  • "Ignoring exceptions is often correct -- many times the best response to an exception is to let the app crash.": It really depends on the application. If you have an uncaught exception in a web application the worst that can happen is that your customer will report seeing an error message on a web page, and you can deploy a bug fix within a few minutes. If you have an exception while an aeroplane is landing, you'd better handle it and try to recover.
    – Giorgio
    Commented Apr 27, 2014 at 15:41
  • @Giorgio, very true. Although I wonder if in the case of aeroplane or similar if the best way to recover is to reboot the system. Commented Apr 27, 2014 at 23:01
4

Checked exceptions are also in ADA.

(Warning, this post contains strongly held beliefs that you might find confronting.)

Programmers don't like them and complain, or write exception swallowing code.

Checked exceptions exist because things can not only fail to work, you can do a failure mode/effects analysis and determine this in advance.

File reads can fail. RPC calls can fail. Network IO can fail. Data can be mis-formatted when parsed.

The "happy path" for code is easy.

I knew a guy at University who could write great "happy path" code. None of the edge cases ever worked. These days he does Python for an open source company. Nuff said.

If you don't want to handle checked exceptions, what you're really saying is

While I'm writing this code, I don't want to consider obvious failure modes.

The User will just have to like the program crashing or doing weird things.

But that's okay with me because 

I'm so much more important than the people who will have to use the software

in the real, messy, error-prone world.

After all, I write the code once, you use it all day long.

So checked exceptions are not going to be liked by programmers, because it means more work.

Of course, other people might have wanted that work done.

They might have wanted the right answer even if the file server failed/ USB stick dies.

It's a strange belief in the programming community that you should be using a programming language that makes your life easier, that you enjoy, when your job is to write software. You job is solving someones problem, not letting you engage in programmatic Jazz improvisation.

If you're an amateur programmer (not programming for money), feel free to program in C# or some other language with no checked exceptions. Heck, cut out the middle man and program in Logo. You can draw pretty patterns on the floor with the turtle.

15
  • 6
    Nice rant you got there.
    – Adam Lear
    Commented Nov 16, 2010 at 3:22
  • 2
    +1 "None of the edge cases ever worked. These days he does Python for an open source company. Nuff said." Classic Commented Dec 15, 2010 at 17:02
  • 1
    -1 You mixed a rant about bad programmers with checked exceptions. C# doesn't have checked exceptions but it doesn't mean it doesn't take corner cases and errors seriously. You can still handle exceptions in C#. C# just wont allow API designer to force the programmer to handle the exception in the calling layer. Not all errors are recoverable. A missing file might be because user typo'd it and user just has to change the name. Or it might be that someone deleted it and the program cannot work anymore so it has nothing else to do than crash.
    – palto
    Commented Jun 12, 2012 at 13:58
  • 4
    @ThomasEding Java forces me to handle the exception where the method is called. It is very rare that I actually want to do something about it in the calling code and usually I want to bubble up the exception to the error handling layer of my application. I then have to remedy it with either wrapping up the exception in a Runtime exception or I have to create my own exception. Lazy programmers have a third option: just ignore it because I don't care. That way no one knows the error happened and the software has really odd bugs. That 3rd one doesn't happen with unchecked exceptions.
    – palto
    Commented Oct 10, 2012 at 6:35
  • 5
    @ThomasEding Doing that will change the interface of everything above which reveals implementation details needlessly to every layer of the application. You can only do that if the exception is something you want to recover from and it makes sense in the interface. I don't want to add a IOException to my getPeople-method because some configuration file might be missing. It just doens't make sense.
    – palto
    Commented Oct 11, 2012 at 18:32

Not the answer you're looking for? Browse other questions tagged or ask your own question.