Bruce Eckel is Wrong

Every time the subject of checked versus runtime exceptions comes up, someone cites Bruce Eckel as an argument by authority. This is unfortunate, because, as much as I like and respect Bruce, he is out to sea on this one. Nor is it merely a matter of opinion. In this case, Bruce is factually incorrect. He believes things about checked exceptions that just aren’t true; and I think it’s time to lay his misconceptions to rest once and for all.

Let’s see exactly what Bruce’s mistake is. The following is an extended selection from Thinking in Java, 4th edition, pp. 490-491:

An exception-handling system is a trapdoor that allows your program to abandon execution of the normal sequence of statements. The trapdoors used when an “exceptional condition” occurs, such that normal execution is no longer possible or desirable. Exceptions represent conditions that the current method is unable to handle. The reason exception-handling systems were developed is because the approach of dealing with each possible error condition produced by each function call was too onerous, and programmers simply weren’t doing it. As a result, they were ignoring the errors. It’s worth observing that the issue of programmer convenience in handling errors was a prime motivation for exceptions in the first place.

One of the important guidelines in exception handling is “Don’t catch an exception unless you know what to do with it.” In fact, one of the important goals of exception handling is to move the error-handling code away from the point where the errors occur. This allows you to focus on what you want to accomplish in one section of your code, and how you’re going to deal with problems in a distinct separate section of your code. As a result, your mainline code is not cluttered with error-handling logic, and it’s much easier to understand and maintain. Exception handling also tends to reduce the amount of error-handling code, by allowing one handler to deal with many error sites.

Checked exceptions complicate the scenario a bit, because they force you to add catch clauses in places where you may not be ready to handle an error. This results in the “harmful if swallowed” problem:

try {
// ... to do something useful
} catch (ObligatoryException e) {} // Gulp!

Do you see the mistake? It’s a common one. Let me repeat it, so it’s really obvious [emphasis mine]:

Checked exceptions complicate the scenario a bit, because they force you to add catch clauses in places where you may not be ready to handle an error.

This is false. You are never forced to add catch clauses where you are not ready to handle an error. This isn’t a matter of opinion. It’s a matter of fact. Checked exceptions do not require catch blocks. They require a catch block OR a throws declaration. Eckel’s entire argument is based on ignoring the possibility of a throws declaration.

While Bruce is absolutely right that you should not catch an exception unless you know what to do with it, this in no way means that you should insert a catch block everywhere a checked exception may be thrown. If you aren’t ready to handle an error at one place, let the exception bubble up. If a checked exception is thrown inside a method where you are not ready to handle it, then the correct response is to add a throws clause to the method indicating that the exception will bubble up from that method. For example,

 public void doSomethingUseful() throws ObligatoryException {
   // ... do something useful that throws an obligatory exception
} 

You do not and should not insert a catch block in a method where you cannot do anything reasonable in the catch block. Checked exceptions never meant that every exception had to be caught as soon as it was thrown. It is perfectly acceptable to declare that a method throws a checked exception. Indeed, this is exactly how exceptions are meant to be used. It warns whoever calls your method that they need to be ready for this exceptional condition, and they either need to catch it and handle it themselves; or, they themselves need to declare that they throw it so that they warn their callers.

Yes, if it were true that every checked exception needed to be caught immediately, then checked exceptions would be incredibly inconvenient. However, experienced Java programmers don’t do this. Catching each and every checked exception at the first opportunity is a sure mark of a novice Java developer.

Occasionally, you’ll override a method inherited from a superclass or implement a method declared in interface that does not declare it throws the checked exception that your method throws and thus can’t throw the correct exception. In this case alone, it may be acceptable to wrap the exception in either a checked exception that the original declaration declares or in a runtime exception (if the original declaration does not declare any appropriate checked exceptions). For example,

   @Override
    public void doSomethingUseful() {
        try {
     // ... do something useful that throws an obligatory exception
        } 
        catch (ObligatoryException e) {
            throw new ObligatoryRuntimeException (e);
        }

However, you still don’t need to handle the exception before you’re ready for it.

I will note that this situation is a failure of design. When you’re forced to do this, one of two things is broken:

  1. The superclass/interface was not designed properly for extension. Specifically it did not take into account the exceptions overriders/implementers might reasonably want to throw. The method likely should have been declared final and probably shouldn’t be extended at all.
  2. The overriding/implementing method is violating the contract of the method it overrides/implements by doing something it really should not be doing.

A good example of the latter would be letting an IOException wrapped in a RuntimeException escape from the run() method of java.lang.Thread or java.lang.Runnable. These methods do not have sufficient context to handle such an exception, but something further down in the call chain does. The exception should be handled before it bubbles all the way up (though not necessarily in the same method where it’s first thrown).

In a method properly designed for extension, an empty throws clause (or a throws clause that does not match the actual exception) indicates that callers of that method cannot handle and do not expect such an exception. An overriding method that throws a new exception is violating the contract by failing to handle it, the same as it would were it to restrict a precondition or loosen a postcondition. (In essence, this is another form of loosening a postcondition.)

Eckel is not the only one to make the mistake of assuming that checked exceptions must be immediately at handled at the first possible opportunity. For example, he cites Barbara Liskov and Alan Snyder explaining their decision not to include checked exceptions in CLU:

requiring that the text of a handler be attached to the invocation that raises the exception would lead to unreadable programs in which expressions were broken up with handlers

True. Requiring that the text of a handler be attached to the invocation that raises the exception would lead to unreadable programs. Fortunately neither Java nor checked exceptions require any such thing. When handlers are appropriate they can usually be moved to the end of a method, far away from the the invocation that raises the exception. When handlers are inappropriate, you use a throws clause instead. Immediately following every statement that can throw an exception with a catch block is bad form on a par with goto.

Liskov and Snyder continue:

“We felt it was unrealistic to require the programmer to provide handlers in situations where no meaningful action can be taken.”

Also very true, but of course, checked exceptions do not require the programmer to provide handlers in situations where no meaningful action can be taken. When no meaningful action can be taken (out of memory error, stack overflow, class not found, etc.) Java programs throw Errors, not checked exceptions, not even runtime exceptions. Checked exceptions signal environmental problems that programmers cannot prevent or predict, should test for, and most decidedly can handle. To choose the most extreme example, if a production-worthy database system is writing a file and the disk fills up, it should handle the condition gracefully without corrupting the database. A disk full error is neither unforeseeable nor unmanageable. Most checked exceptions aren’t even that tricky to respond to.

What checked exceptions actually do require is that any method that can throw a checked exception warn its callers that the exception may be thrown. That’s all. A checked exception is nothing more and nothing less than part of the return type. Methods may return normally or they may throw exceptions. It makes just as much sense to specify the exceptions that can be thrown by a method as it does to specify that a method returns an int or a String. A method that does not declare the exceptions it throws is incomplete.

A lot of us didn’t really get checked exceptions when Java was released in the mid-nineties. It was a genuinely new idea that I don’t think any programming language before had foreshadowed. Liskov and Snyder wrote the paper quoted here in 1979, and their quotes make sense if you assume they simply didn’t conceive of having different kinds of exceptions in the language. if you only have one kind of exception then it makes sense for it to be a runtime exception rather than a checked exception.

Personally, I didn’t really understand how to use exceptions until the first edition of Effective Java was published. But it’s been 15 years. That’s long enough for the message to get out. In 2010 we know better. Proper error handling requires distinguishing programming errors (runtime exceptions) from environmental problems (checked exceptions). Proper error handling requires correcting programming errors and writing handlers for unpreventable environmental conditions. Proper error handling requires knowing when to catch and knowing when to throw. If you try to work with only one kind of exception, or try to get by with only catch but no throws, then exceptions are going to seem very ugly and inconvenient. But if you use checked and runtime exceptions, and use catch and throws, then your error handling code will be far cleaner, safer, and more maintainable. Error handling without checked exceptions and throws is like arithmetic without * and /. Sure, you can do it, but why would when you when using the features the language offers makes life so much simpler?

59 Responses to “Bruce Eckel is Wrong”

  1. Andrew Thompson (lordpixel) Says:

    Well said. The only thing I’d add is that the JDK is replete with examples of one other good technique: component or layer exceptions. The problem that can occur with adding exceptions to ‘throws’ is if exceptions bubble up several levels, you can end up with several coming together in one method:

    public void someCoordinatingMethod()
    throws ObligatoryException, SomeOtherObligatoryException, SomeThirdObligatoryException etc.

    In many chases this is an indication that some of the exceptions should probably have been handled already, but sometimes they are all genuinely problems the lower level code cannot reasonably handle. The programmer calling someCoordinatingMethod() then either has to write 3 separate catch blocks, usually all with virtually identical logging or GUI code, or they write ‘catch (Exception e)’ which masks all the problems and ends up catching all RuntimeExceptions too.

    The solution to this can be seen in things like SQLException, JNDIException, JMSException and even IOException etc. In these APIs all exceptions extend a common superclass exception. This is ideal because the caller now has a choice – e.g. if they don’t care about the specific problem that occurred with the messaging, he or she can simply write ‘catch JMSException’ and handle everything uniformly.

    On the other hand, maybe JMSSecurityException or MessageNotWritableException need custom handlers… well in that case


    try {
        //do some JMS
    }catch (JMSSecurityException jse) {
        //handle specially
    } catch (JMSException je) {
        //handle all others generically
    }

    The point is the caller gets to choose whether generic or specific error handling is appropriate, or he or she can simply write ‘throws JMSException’ (or throws ‘MyComponentException) and toss it up to the next layer if it makes sense.

    The canonical example where they completely screwed this up in the JDK was reflection… ever seen code like this?

    try {
        //call some method by reflection
    } catch (ClassNotFoundException cnfe) {
        //tedious repeated code
    } catch (IllegalAccessException iae) {
        //tedious repeated code
    } catch (InvocationTargetException ite) {
        //actually this is the real exception thrown by the method you called
    } catch ( NoSuchMethodException nsme) {
        //tedious repeated code
    }

    Well, you probably haven’t seen code like that, because most people write:

    try {
        //call some method by reflection
    } catch (Exception e) {
        //failure!
    }

    Of course, this rolls up the error handling for reflection itself with the error handling for the method you called, which can be found in InvocationTargetException.getCause(); Sometimes this is OK – failure is simply failure and the handling is uniform – and sometimes it isn’t – you want to handle plumbing problems differently from the called method throwing an exception.

    The good news is better late than never they finally fixed this in Java 7 by making all the reflection exceptions have a common superclass: ReflectiveOperationException.

    But I am in two minds whether they should hand included InvocationTargetException – it isn’t really part of the reflection mechanism going wrong, it’s a wrapper for exceptions from the called method, and maybe should have been kept separate to provide a hint you need to think about handling it differently. But then again, maybe you don’t really handle it differently all that often?

  2. Stephane Galles Says:

    Andrew,

    You’ve perfectly described the reason that make a programmer use the “MyComponentException” scheme.

    I used to throw this kind of checked exception too, for large systems with many layers, to try to fight the long checked exception lists in method signature and to keep the right level of abstration in every layer.

    But one day I realised that most exceptions in large system must anyway hit the fault barrier, and the “throws MyComponentException” scheme is then everywhere in all components, in all layers.

    In this situation, when you read the code, you just see “throws MyComponentException” everywhere. And the level of abstraction is so high that the signature of the method does not tell you anything about what could happen in the lower layers. IMHO it is almost like the infamous “throws Exception”, it does not help. So you just let the MyComponentException bubble up once again, and add an other signature with this exception.

    That’s why I humbly tend to agree with Bruce Eckel. Most of the time I prefer an empty “throws” clause that implicitly says “something might happen”, instead of a verbose throws clause with “MyComponentException” that also says “something might happen” and you must also repeat “something might happen” once again.

  3. Michael Langford Says:

    >n this situation, when you read the code, you just see “throws MyComponentException” everywhere. And the level of abstraction is so high that the signature of the method does not tell you anything about what could happen in the lower layers. IMHO it is almost like the infamous “throws Exception”, it does not help. So you just let the MyComponentException bubble up once again, and add an other signature with this exception.

    Sounds like you need more different exceptions Stephane, “throws MyComponentLogFileOnFireException”, “throws MyComponentNetworkDoesntExistException” etc.

  4. brazzy Says:

    I’m with Bruce all the way. Forcing you to add a “throws” is nearly as bad as forcing you to catch. Checked exceptions pollute your code with exception declarations at the wrong level of abstraction and sabotage the concept of exceptions. They may have been an experiment worth doing, but I wish it had been done in a less widely used language, because it failed horribly and we all have to suffer for it.

  5. MeBigFatGuy Says:

    +1

    Having a pathologic desire to always throw runtime exceptions basically says ‘i dont care what happens in the exception case, let the user get screwed. I might handle it, i might not, doesn’t really matter to me.’ Unfortunately it seems, that is the prevaling opinion. I chalk it up to laziness, mostly.

  6. Barry Kelly Says:

    I think you’ve very much mistaken.

    Checked exceptions are problematic because they version poorly, they implicitly presume the wrong model of exception handling, and more importantly, they prematurely decide the application’s desired policy for error handling by encoding the “checkedness” in the type itself, where it is not available for configuration by the programmer.

    The poor versioning is obvious. You say: “The superclass/interface was not designed properly for extension. Specifically it did not take into account the exceptions overriders/implementers might reasonably want to throw” – and the only problem with that is the well-known difficulty in predicting the future.

    But actually, it’s more subtle: exceptions are usually a desired encapsulation violation. When programming to an abstract interface, you don’t want to know the details of how it’s implemented, but all the ways it can fail are a function of how it’s implemented. You can’t reasonably require the design of the most abstract levels of the system to predict every possible low-level implementation failure and state them out long-hand; the only reasonable implementation would be “throws Exception”, which defeats the whole point of checked exceptions.

    By presuming the wrong model of handling, I’m referring to the burden of creating a tunnel through the type system for your exception type between the point of the throw and the point of the catch. This burden is set up to optimize for catching sooner rather than later. But the thing is, usually you never want to catch; usually, the only exception catching you want done is at the highest levels of the system, in an event loop or request dispatcher. If you were expecting an exception you’d want to catch, the situation isn’t exceptional; instead, ideally you shouldn’t be using an API that throws. .NET’s pattern of e.g. Int32.Parse() vs Int32.TryParse() exemplifies this.

    You try to argue against this with the distinction between runtime errors and exceptions: “checked exceptions do not require the programmer to provide handlers in situations where no meaningful action can be taken. When no meaningful action can be taken Java programs throw Errors”. And this brings me to my third point. The determination for whether meaningful action can be taken varies from program to program, and is encoded in the very exception handlers themselves – i.e. it’s the programmer who should make that choice, not the people who defined the relevant exception types.

    All your examples of error – out of memory error, stack overflow, class not found, etc. – actually make more sense as reasons to completely terminate the application, rather than make any attempt to catch. They’re not really errors so much as panics; no one could argue against the fact that meaningful action can’t be taken.

    But most of the time, meaningful action can’t be taken; and even when it can, it often isn’t. Consider your web browser. A whole host of things need to happen between entering a URL and the stuff coming up on screen. But what can the web browser meaningfully do about these things? Failure to resolve DNS? Failure to connect? 404? Failure to log in? The best the browser can do is (a) try to carry out your intentions, and (b) if it failed, report back to you with the reasons why. Server programs are usually little different; they try to carry out the request, and return a more or less detailed error reply in the case of failure, with more details sent out to log.

  7. Brian Slesinsky Says:

    I’ve found it’s fairly rare that you can simply let an exception bubble up. The problem is that method calls cross abstraction boundaries between layers more often than not, so catching and wrapping exceptions happens very frequently, leading to lots of boilerplate.

    My current approach is to create an UnavailableException that’s used in every layer, and immediately catch and wrap any other kind of exception as UnavailableException. As a result, all methods in my app are declared to throw the same exception, if they throw anything at all, and it’s easy to let exceptions bubble up across layers. Method declarations only distinguish between methods that can fail and methods that can’t, but that’s usually sufficient.

    However, this isn’t all that much different than assuming any method can fail and just using runtime exceptions.

  8. Bruce Eckel Says:

    Elliotte suggested I comment on this, but I can hardly do better than what Barry Kelly says above; he has analyzed the arguments more completely than I think I’ve done. And as Elliotte points out, I should have said “They require a catch block OR a throws declaration.” Even including those I would still make the same argument — that requiring the programmer to intervene when something hasn’t gone wrong is not good language design.

    My own experience did not come from careful argument as Barry Kelly has done. Instead, it was from working with Python, where exceptions automatically go up (without requiring any coding by the programmer) until you explicitly catch them, at the point where you can do something about it. That just seemed to work better (nothing particularly bad happens, and it’s much simpler and cleaner), so I went back and tried to understand why Java used checked exceptions, and couldn’t come up with a good reason.

    I would actually guess that checked exceptions came from C++, which has exception specifications which are not enforced (they’re just informational). I suspect that in Java they thought it would be a good idea to have the compiler check them and enforce their proper use. Like many of the questionable features in Java, I think it was an experiment.

    I will also re-assert that if checked exceptions are such a great idea, why haven’t we seen them in new languages? Maybe we have and I haven’t been paying attention, but I don’t think so; to the contrary I have talked to at least one language designer (Anders Hejlsberg, for C#) who considered them and left them out.

  9. Joshua Says:

    Although the throws argument does allow some flexibility with checked exceptions, you cannot use it when you are implementing to an interface.

  10. John Bayko Says:

    I think the problem with exceptions in general is that they mix together program flow and diagnostic data, and that makes people unsure how to treat them. On one hand, an exception that exits a method is a return value, and thus without question part of a method’s signature – unless you use a dynamic language that doesn’t declare return values, or even have a single return type (could be a string, could be a list of open files). But Java is statically typed, so methods have declared return types, which logically includes exceptions.

    On the other hand, as a program flow construct that was designed to transparently separate exception sources from exception handlers, you’d really prefer the plumbing (which you don’t care about) to remain hidden behind the walls. And that includes when it crosses methods, in the same way you don’t expect plumbing between rooms to have to exit the walls and go through the same doorways you walk through.

    All told, I prefer the Java checked exceptions, by virtue of the fact that it at least promotes better code. At the very least, sometimes the effort to ignore it exceeds the effort to handle it correctly. If you think statically checked types improve code, then statically checked exceptions also do.

    The other argument from Bruce Eckel, “why hasn’t another language used them” only reminds me of the type checking of Ada, versus C. Ada’s type checking is far more comprehensive, and eliminates entire classes of errors, but C’s much looser checking became the standard – initially. But even C’s type system has been gradually tightened over the years, and Java and C# go further (enums and ints are no longer equivalent), approaching Ada’s level of type checking. So the comparable question “if strict type checking is any good, why hasn’t any other language adopted it?” is answered simply by the fact that eventually, over the years, what once seems like a useless restriction can become adopted by slow, hard-learned group experience.

    So it may take a few decades before you can legitimately use the “why don’t other languages have checked exceptions?” question.

  11. Elliotte Rusty Harold Says:

    Joshua,
    See When you can’t throw an exception for a detailed analysis of exactly what to do when implementing an interface that doesn’t have the throws clause you want.

    Barry,
    You need to distinguish between a java.lang.Exception and a java.lang.Error. This is critical. Exceptions are recoverable. Errors rarely are. Meaningful action can always be taken on an exception but usually not on an error. There is no distinction between runtime and checked exceptions in this regard. The distinction between runtime and checked exceptions is exclusively about whether they indicate a bug in the program (runtime exception) or an unpredictable environmental condition (checked exception). The reason catch blocks at some level of the call chain are needed for checked exceptions is because they cannot be eliminated by better coding practices. Catch blocks for runtime exceptions are needed only as defense in depth against program bugs. Runtime exceptions should be logged and the problem that caused them fixed so they don’t reoccur.

    Your claim that “usually, the only exception catching you want done is at the highest levels of the system, in an event loop or request dispatcher.” is exactly the problem checked exceptions are designed to solve. Many programmers don’t want to deal with exceptional conditions and would prefer to ignore them. Checked exceptions makes it harder to ignore them. If you’re ignoring them until the top level of your code, you’re probably doing something wrong. If you never want to catch exceptions, then your code is a lot less robust than it should be. Both extremes–catch all exceptions as early as possible and catch all exceptions as late as possible–are equally wrong. The moderate position is to catch each exception at the point where it is best dealt with. Sometimes this is the top or the bottom of the call stack, but more often it’s somewhere in between.

    Exceptions are not an encapsulation violation. They are part of the contract of a method. If they expose implementation details, then the exception should be changed to a different (but still checked) exception that does not expose implementation details. But under no circumstances should you wish away that uncontrollable environmental problems such as I/O issues.

    The web browser example is a good one, but it does not indicate what you think it does. For instance, suppose a web browser gets an UnknownHostException. That should be dealt with, either with a retry or by alerting the user. The alert to the user, if that’s the response chosen, should be specific to the problem. It requires a very specific set of actions in the browser’s GUI. It should not be delegated to a generic error handler somewhere close to the top of the stack or, worse yet, allowed to bubble up to main() and shut down the browser. Java is doing programmers a favor by indicating where these unpredictable environmental problems can arise, and it is doing users a favor by making it harder for programmers to pretend these problems won’t happen.

    Bruce,
    The explicit reason for adding checked exceptions to Java was to protect users from careless programmers who did not handle unpredictable problems. They were a safety feature for a language that cared a lot more about safety and security than any language has before or since. If other languages have not chosen to add them, it is because those other languages have chosen to prioritize the preferences of developers over the needs of end users.

  12. Squirrelsewer Says:

    For all of the checked exception fans: can you give us some idea of which Exceptions you commonly catch and handle? What % of checked exceptions are you able to handle?

  13. Joseph Garvin Says:

    @Bruce: In C++ throw specifications are enforced, just not at compile time. Throwing an undeclared exception (provided that the function has a throws declaration at all) will cause a call to abort().

  14. Inceptor Says:

    If, by definition, an exception is a signal not defined in the protocol (the interface),
    including the exception in the protocol (a “checked exception”) would make it … a non-exception …

    Checked exceptions simply expose implementation details.
    Don’t use ‘em.

  15. TE Says:

    I agree with Barry, who gets to the essence of the problem with this: If you were expecting an exception you’d want to catch, the situation isn’t exceptional. Exactly. There is nothing wrong with error codes or some equivalent scheme. And there is nothing about unchecked exceptions that prohibits their use as a signal for retry or failover. But unchecked exceptions are far easier to deal with in code that has to be maintained.

  16. Andrew Thompson (lordpixel) Says:

    Exceptions are absolutely a part of the API of a program. Exceptions are not signals, they are fully developed objects with state and methods which are just as much a part of the API as the parameters and return values of methods. Interfaces should declare what exceptions are thrown if normal completion and return is not possible.

    Nor must exceptions of any kind necessarily leak implementation details. Here’s an example of a horrible exception that leaks implementation details like a sieve because the error codes are completely vendor specific SQLException.getErrorCode(). Here’s Spring’s take on the same concept DataAccessException. Either can be used to recover from errors like deadlock – a common, predictable, recoverable error condition arising from environmental conditions outside of the project’s control, but SQLException is horribly vendor specific whereas DataAccessException doesn’t even expose whether a database is in use or not. From Java 6 onward you can see they’ve started to rehabilitate SQLException by adding DataAccessException subclasses to it.

    In the SQLException/DataAccessException example it happens that the poorly designed exception is the checked Exception and the better designed one is a RuntimeException. But if the opposite were true, it wouldn’t change which exception has the better API overall. Whether an exception exposes an implementation detail depends entirely on whether it is well designed, not whether it is checked.

    Modern programs are many layers deep. Applications call locally written libraries that call vendor libraries that call platform code. Each layer should be making the following decision about errors:

    (i) can I handle this error at this level in the code

    (ii) is it appropriate to pass the error to my caller, i.e. might my caller be able to handle it, or should I not throw it as is because i will be leaking an implementation detail

    (iii) so alternately should I wrap the exception in another exception that my caller can understand – communicating the problem without leaking the implementation details

    Again, it doesn’t fundamentally matter whether these exceptions are checked. A careful programmer could in theory consider every exception thrown by every method called and choose to catch it, declare it in the throws clause or wrap it appropriately whether it is checked or not.

    But that’s theory – in practice if everything is a RuntimeException several things occur

    The compiler isn’t able to tell the programmer which exceptions to focus on because they might be recoverable.
    The compiler isn’t able to check the exception is handled on all code paths in a method for you, so you get subtle corner cases where you don’t handle the except even though you intended to.
    Since most programmers aren’t dedicated enough to declare RuntimeExceptions in the throws clause, there’s no way for a programmer 2 layers or more above to know what the possible set of RuntimeExceptions thrown is unless they have access to and can read all of the code. The API is incomplete – its error conditions are unspecified. By hiding what is thrown, the programmer has little choice: catch everything, let everything go or guess the set of RuntimeExceptions to catch and hope the implementation doesn’t change

    Several posters seem to feel the goal is to let everything go out through every layer and reach a top level error handler, but a top level error handler is very generic and is there as a last resort, because it is better to have some handler for things and not just dump them to the console where no one is looking. Just throwing up a dialog or a line in a log file which reads ‘What you were trying to do didn’t work due to a FooException’ is a bare minimum, not the end goal for error handling. Convenient for programmers, yes, but infuriating for users.

  17. Marc Ramsey Says:

    For what it’s worth, throw/catch apparently first showed up in MacLisp sometime around 1974. Having written a few CLU programs early on, I remember throws being present in the language, but I don’t think it was enforced at compile or runtime. Ada had the equivalent of throw/catch (raise/exception) from the beginning, but no equivalent to throws. I worked on code generation and runtime support code for the first two non-academic Ada environments, and the expectation at the time was that all Ada programs would be globally optimized, so the set of exceptions that could be generated by a given code segment could be pretty much unambiguously determined without using throws. Ada had a standard pragma that could be used to suppress runtime checks for specific exceptions, to cover the limited cases where foreign code or something else introduced ambiguity. The Modula-3 language from the mid-80s had checked exceptions (the RAISES clause) that were enforced, so I believe it was clearly the first language where this was fully implemented, nearly a decade before Java…

  18. Stephane Galles Says:

    For what it’s worth too and speaking of other languages, Scala is built on the JAVA ecosystem, you can compile with JAVA libs, but Scala does not require you to catch checked exceptions. Scala simply see JAVA checked exceptions as RuntimeException. Martin Odersky has decided to create a Scala compiler without checked exceptions ; there must be some good reason.

  19. Inceptor Says:

    @Andrew Thompson: if a checked exception is “part of the API of a program”, as you put it, then it is not an exception since it is expected.
    Instead, it is just an awkward way to communicate results defined by the interface.

    If the language allowed tuples as return values (like many other modern languages, e.g. Scala), this would be even more obvious.

  20. Edwin Says:

    I sent a note to Martin Odersky; maybe he is willing to participate …

    From my own experience, I am really not sure which side to lean on.

    I am right now working on a somewhat huge project. “Huge” in terms of:

    a) a lot of people (working in multiple teams spread around the globe)

    b) a lot of different features / “domains”

    Its less about “much” code … more about merging the knowledge of 5 different domain experts into ONE application.

    Basically I see the two worlds collide: we have two local teams at our site; we could sit together and defined a “well defined” interface; and we discussed exceptions for quite a while. We ended up and decided: “we want to have a small set of different exceptions; and all these exceptions have to be used in the throw clause”. I am responsible for connecting this code to “the other side” (that team is on the other side of the ocean) … and the other side is using a mix of such “specialized” exceptions … and our companies own “RootException” class.

    I found it really annoying to see:

    a) our throws clauses got longer and longer … and as we have a very complicated library setup … that is a real pain. Two library and build systems … and any interface change becomes very painful.

    b) The folks “on the other side” tend to not at all look at our long exception list. All our exceptions are derived from “RootException”, and that is what they catch.

    c) Typically, there is not too much that you can do in terms of “recovery”. I call a method and it tells me “RessourceException” … so what can i do? Not much. I think in all our code there are just a few occasions where we actually react differently based on the exception type.

  21. Edwin Says:

    OK; Martin tells me: the main reason Scala isnt doing Java exceptions … is the fact that they regard the Java solution as technically deficient. Instead of dealing with this technologoy, Martin decided to “leave out” exceptions in Scala for the moment … and he is looking into better solutions.

    So hopefully, some day, some future Scala version will surprise us with a better solution.

  22. Daniel Says:

    While Bruce Eckel’s books are among the best I read on programming in general, this is a topic where I don’t agree. I don’t think the checked exceptions are a failed experiment.
    I actually believe much of the success of the Java platform on the server side is a cause of the fact the programmers are forced to think about the error cases early. Are there mistakes in how the exceptions are implemented in Java? Oh yes! Is it possible to write elegant and good code without checked exceptions? Sure! But let’s face it, the vast majority of the programmers tend to leave error handling for later or never. With Java you are forced to do something even if it is just an empty block. Of course the empty block if left like that will be worse than a RuntimeException. But Java is used most of the time on the server side in the enterprise and in this environment usually the programmers obey some sort of rules designed by an architect or senior developer and then the code is subject to code inspections so most of the time the exception is in the end treated somehow in a way that will allow the server application to continue to run.
    A lot of people fail to realize that it is not the same to write server side code where the server runs unattended or to write GUI applications. For example Anders Hejlsberg (C#) gives examples where he doesn’t see the point of dialog boxes popping up for checked exceptions. There are no dialog boxes in server applications. I could continue with my reasoning but if you are interested you can read my old series on Java exceptions on my site.

  23. Andrew Thompson (lordpixel) Says:

    @Inceptor

    To me, your argument sounds like you are just playing games with the English language. Just because something is ‘expected’ does not make it ‘non-exceptional’. I expect that when I send a SQL query to the database, sometimes I will be chosen as the deadlock victim and my transaction will be rolled back. This is ‘exceptional’ in the sense the normal case is my transaction commits, but expected behavior for most database systems. Similarly, if I save a file the common case is it works, but sometimes something exceptional occurs and the disk is full or the user does not have permission to write the directory. These are exceptional, but a good programmer expects and handles these errors.

    None of this relates to whether an exception is checked or not.

    If you’re proposing we use tuples instead of exceptions to communicate results or errors, then I’m afraid I truly disagree. Let’s assume something like this:

    class ErrorClass {
        public boolean isNoError() { ... }
    }

    class ValueOrError {
        private final R result;
        private final E error;

    public ValueOrError(R result, E error) {
        this.result=result;
        this.error = error;
    }

    public R getResult() {
        return result;
    }
    public E getError() {
        return error;
    }
    }

    void someMethod(Data someData, String filename) {

        ResultOrError result = openFile(filename);
        if ( !result.getError().isNoError() ) {
            log.error(result.getError());
            //etc. handle possible errors
            } else {

            File f = result.getResult();
            ResultOrError result = writeData(f, data);
            if ( !result.getError().isNoError() ) {
                log.error(result.getError());
                //etc. handle possible errors
                    } else {

                ResultOrError result = flush(f);
                if ( !result.getError().isNoError() ) {
                    log.error(result.getError());
                    //etc. handle possible errors
                            } else {

                    ResultOrError result = close(f);
                    if ( !result.getError().isNoError() ) {
                                    log.error(result.getError());
                        //etc. handle possible errors
                    }
                }
            }
        }
    }

    I really hope that’s not what you’re proposing as a better alternative to exceptions. Syntactic support for tuples won’t improve the control flow in the code above. I used to have to write code in C like that and I never want to go back to those days. try and catch are light years ahead.

  24. GabeMc Says:

    I have to disagree. The issue with throws is that the method signature changes. All inherited classes (including ones that you may not own), must change their code to handle exceptions which (even in subclasses) may never be thrown. It becomes particularly annoying when you have to waste code catching errors you know will never be called.

  25. Sakuraba Says:

    Checked exceptions do more harm than good.

    Oracle kills the JDK with a paywall and we all should learn Python to survive in 2010-2020.

    No need to discuss all this. Nuff said.

  26. Cedric Says:

    Well said, Elliote.

    Checked exceptions “pollute” the code as much as “error checking pollutes the code”. It’s a *good* thing. Checked exceptions force the programmer to think about error cases as soon as they possibly can, which results in more robust code.

    People arguing that there should be only one type of exceptions (runtime ones) are basically saying it’s okay to ignore return values when you call a method. This lazy approach in languages that predate exceptions (e.g. Windows and HRESULT) is what led to such unreliable software.

    As for C# not having checked exceptions: Anders has explained many times that it was done so for backward compatibility (C# runs on the CLR, which supports many languages, and they were forced to take a “least common denominator” approach, so they couldn’t use checked exceptions — mostly because C++ doesn’t support them).

    The fact that a lot of the exceptions are not recoverable and therefore should be runtime exceptions is a different problem, but one that leads so many people to condemn checked exceptions altogether instead of just spotting when they are used incorrectly.

    Checked exceptions are an absolute requirement to produce robust code.

  27. Troy Says:

    -1
    >>Checked exceptions complicate the scenario a bit, because they force you to add catch clauses in places where you may not
    >>be ready to handle an error. This is false.
    Actually it is not false you assume that you can change the signature of your method to include a throws statement you have no idea how much code this can break in a project of real scale not something you hack by yourself for fun. A lot of the code you deal with you have no control over and can not force a change. A signature is a contract the throws clause is part of that contract you can not change it on a whim it might be defined by third parties or break to many other peoples code. So yes you are forced to catch that checked exceptions and yes you usually do not have enough knowledge in that point of the code to properly handle the exception so you usually log it or re throw it wrapped up as a Runtime exception. Only someone who has never worked on a big java project could say any different.

    Checked exception are not composable and even though they espouse a more pure view (very much like Haskell monads) of the world where certain things should not compose. It is not a very practical way to look at things when you just need to to get things done.
    You are stuck with a current system you need to extend its capabilities quickly within a deadline your customer could care less about your puritan views. Practicality beats purity.

    Checked exceptions are definitely a failed experiements no other language has bothered to steal them if they were such a great
    feature other languages would be imitating them.

    Even Monads have at least some fans they even put Monads into VB.NET

    Troy

  28. Brian Hartin Says:

    I would submit that many Java programmers are J2EE programmers, and hence deal with database access quite frequently. I think that this context makes checked exceptions seem more desirable, because there are a whole host of situations that need explicit recovery or special handling, such as locked rows, duplicate values, concurrency issues (your row has been updated beneath you), transactional concerns, etc. I have, myself, often been grateful for the ability to have exceptions which carry meaningful information (beyond just a message) and to know that a controller method will be ‘reminded’ (forced) to handle a concurrency situation properly, displaying an appropriate error message and/or choices (‘Someone else has updated this item…’).

    While I can understand many of the arguments against them, the ‘new languages don’t use them’ is not very convincing to me. These languages and frameworks have widely varying purposes and cultures. Many of these actually express the intention of avoiding the level of rigor and safety that accompanies Java/J2EE, in favor of other gains such as more rapid development and simpler APIs. That’s a good thing, I think, for many purposes, but it needs to be considered when comparing their exception-handling approaches.

  29. Inceptor Says:

    @Andrew Thompson: (sorry for my poor English)

    My point was simply that exceptions is not part of the interface/contract/protocol. Nothing else.

    Of course you should use exceptions.
    But when communicating anything defined by the interface, it should not use exceptions.

    I agree that your example stinks badly.
    It should use exceptions to signal irrecoverably implementation dependent errors.

    If you for some reason don’t want to use exceptions (runtime exceptions),
    this would be a cleaner version (IMO), using a tuple in the open-stmt, in an imagined language:


    def writeSomeData(file, data) {
    def res = openWriteAndClose(file,data)
    if (!res.success)
    log.error(res.message)
    return res
    }

    def openWriteAndClose(file, data) {
    def (fileHandle, res) = open(file)
    if (res.success)
    return writeAndClose(fileHandle, data)
    else {
    return res
    }
    }

    def writeAndClose(fileHandle, data) {
    def res = write(fileHandle, data)
    if (res.success)
    return flushAndClose(fileHandle)
    else
    return res
    }

    def flushAndClose(fileHandle) {
    def res = flush(fileHandle)
    if (res.success)
    return close(fileHandle)
    else
    return res
    }

  30. A.J. Wilson Says:

    Even though someone requested what percentage of checked exceptions people have meaningful handling for, it seems none of checked exception proponents have been forthcoming with this information yet. About all I have seen is “displaying an appropriate error message and/or choices (‘Someone else has updated this item…’).” To me, this is no more appropriate than showing the original exception message to the user. Proponents of checked exceptions please give some information about how you provide meaningful handling of exceptions and an estimate of what percentage of exceptions you actually can handle in a meaningful manner.

  31. Stephane Galles Says:

    @Brian Hartin

    I wouldn’t have chosen the J2EE database layer as an example for checked exceptions. Hibernate get rid of checked exception in version 3, and hence the JPA API does not use checked exceptions (cf. exceptions of javax.persistence). But I guess that you were talking about JDBC.

  32. Brian Hartin Says:

    @Stephane Galles

    That’s a good point. It’s been several years since I actively worked in Java (I’m doing Ruby now) and I haven’t used Hibernate/JPA.

  33. Ruslan Zenin Says:

    The problem I see that once you selected as a root exception type either RuntimeException or Exception…all child exceptions can be only this kind (either unchecked or checked)…this comes from single inheritance exceptions build upon.

    What I would like to see is the ability to “mark” an exception to what type it is (either unchecked or checked).

    For example:

    @Checked
    MyExceprionClass {}

    So by default, all exceptions are unchecked, and in some cases where API designer really wants the caller check exceptions mark with @Checked.

    This way we can “jump” in the hierarchy of the exceptions from one type to another (without involving single inheritance constraints)

    P.S.
    I’d say in the majority of my projects I have used unchecked exception type…the reason…*much* less pollution of “try {…} catch(e){ don’t know how to handle – rethrow}” nonsense…that we all see a lot in the code.

  34. Axl Says:

    I find exceptions useful but you have to be vigilant and careful to do it properly. I cannot add to any of the comments. However, I’ve started declaring exceptions as follows in my interfaces:

    public interface Interface {
    blah(final Z z) throws T;
    yaddah(final X x, final Y y) throws T;
    }

    Now it is up to the implementer to decide on how formal exceptions should be handled. If I have MyException extends RuntimeException that is thrown by blah(…) I do not have to catch it if I call it from another operation. If I have AnotherOfMyException extends Exception I must catch the exception thrown by blah(…) if I call it form another operation.

  35. Axl Says:

    Hmmmm. I see the comments leave filter out < and > blah(…) should be <T extends Throwable> void blah(…) throws T and yaddah(…) should be <T extends Throwable> yaddah(…) throws T.

  36. Links « Otaku, Cedric's weblog Says:

    […] Bruce Eckel is WrongChecked exceptions are a good thing, learn to use them properly. […]

  37. Bruce Eckel Says:

    Cedric Says: “Checked exceptions are an absolute requirement to produce robust code.”

    I’m pretty sure this says that no language without checked exceptions can produce robust code. So if anyone can find a counterexample, all of the arguments by that poster become questionable. (Perhaps he was being ironic or sarcastic and I missed it).

    Here’s what Anders told me about why he left checked exceptions out of C#: they don’t scale. They seem like a good idea on the small scale, but they get very messy when things scale up (an idea which other commenters here seem to support). He told me that he wouldn’t exclude the possibility of including them at some later point if it makes sense (but that was years ago, regarding C# 1.0 if I remember), which sounds like the same attitude that Martin Odersky took with Scala.

    The culture of Java is that nothing is ever removed. For that matter, nothing is ever acknowledged to be a mistake, and I think that does damage — not to language designers, who are smart enough not to repeat a mistake, but to programmers, especially those new to the profession, who see something and assume that because it is in the language it must be right. That was the reason I spent time researching the topic and making the arguments that I did in Thinking in Java (not just for checked exceptions, but for numerous other topics as well): I find that people are better programmers when they understand the imperfections of their language — they don’t spend time thinking “there must be some way to do this ‘right,’ because no one would make such a mistake in such a heavily-hyped programming language.” Instead, they see a tangled mess of (for example) checked exceptions and think “checked exceptions, right, interesting concept, but doesn’t always work out so well.”

    So nothing gets removed, and most of this argument is thus not that important. Checked exceptions will always be in Java, and most of the people I know who’ve gotten tired of this and other mistakes that are bombastically defended (and everyone has to admit there are inarguably obvious ones like AWT and the first collection classes — the Java designers never to my knowledge apologized for these, but sometimes they replaced them, and maybe the addition of the “wrapping RuntimeException” is another one of those non-apologies), those people have just moved on, staying with the JVM but leaving Java, at least as much as they can. That’s probably the greatest thing the JVM has given us: choice, or at least the possibility of choice. When you outgrow Java, you don’t have to throw away everything you’ve learned or all the code you and everyone else has written. You can move on to Scala or Groovy or JRuby or Jython, etc., and get the best of all worlds.

    And if you really, really love checked exceptions and think that no robust code can be written without them, then Java is the language for you and there’s no need for you to move on, and I can pretty much guarantee that your checked exceptions will never leave the language — it’s not in the culture. But if you are determined that everyone else must believe this and never, ever, wrap a checked exception in a RuntimeException, then you might have your work cut out for you. There are a lot of well-reasoned comments on this post alone that suggest that the argument is not as clear-cut as you might like to think.

    (And a clarification for one or two posters who seem to have misunderstood, thinking I don’t like exceptions: a single, unified error handling mechanism is, I believe, very important if not essential. Thus, I think exceptions are great. It’s the CHECKED exceptions that I think have a lot of problems).

  38. Cedric Says:

    Ok, I probably exaggerated a little bit for effect :-)

    However, I do believe that it’s harder to produce robust code without checked exceptions.

    Encouraging the use of runtime exceptions everywhere is like saying that it’s fine to ignore error codes everywhere.

    Most of the time, it is: a lot of exceptions can indeed never be recovered from.

    But there are a few cases where it is possible to do something about an exception. Not only that, but it’s actually desirable to force the developer to think about this case, so they can decide whether they want to ignore it or handle it. Note that this is the only decision imposed on the developer: “think about this”. They are still free to ignore that exception if they so desire.

    The best example of a good checked exception is FileNotFoundException. Good because it’s very often recoverable, and even when it’s not, you probably still want to do something about it, such as logging it or letting the user know.

    A framework in which FileNotFoundException has become a runtime exception that most methods no longer bother putting in their throws clause is pretty much guaranteed to let some of these exception go unhandled, which I consider a very bad thing.

    There is one thing on which I agree with runtime exception advocates, though: Java uses checked exceptions way too often, even in the JDK (IOException seems to be the most misued one).

  39. Steve Finck Says:

    I believe both Rod Johnson and Joshua Bloch are on the side of using unchecked exceptions as well, so I don’t think Bruce Eckel should be the only one who is cited for being on this side of the argument.

  40. Elliotte Rusty Harold Says:

    I don’t know Rod Johnson; but I do know Josh; and unless he has changed his mind since he wrote Effective Java, he still believes one should “Use checked exceptions for recoverable conditions and runtime exceptions for programming errors.” I actually only half agree with him here. The point about using runtime exceptions for programming errors is correct. However the problem with Joshua’s formulation is that there are, at least arguably, exceptional conditions that are neither programming errors nor recoverable. And there certainly are programming errors that are recoverable. These two categories are neither disjoint nor universal. I think a better formulation is, use checked exceptions for problems arising from the external environment in which a program runs conditions and runtime exceptions for problems arising from the internal environment of the program itself.

    In any case though, I have never heard Bloch state, unlike Eckel, that there should be no use of checked exceptions. Like myself, he falls squarely into the moderate camp of using the right tool for the job at hand. Sometimes that’s a runtime exception and sometimes that’s a checked exception. A Java programmer using only one type of exception is like a carpenter who will only use a hammer and never a screwdriver.

  41. Improving exceptions « Otaku, Cedric's weblog Says:

    […] a recent article called “Bruce Eckel is wrong”, Elliote Harold decided to write a counter-argument to Bruce Eckel’s critique of checked […]

  42. Paulo Silveira Says:

    Hi Cedric

    “A framework in which FileNotFoundException has become a runtime exception that most methods no longer bother putting in their throws clause is pretty much guaranteed to let some of these exception go unhandled, which I consider a very bad thing.”

    On the other hand: going unhandled will make this exception “fail fast”. This is really good! We would put a catch block only if we realize that we really need it and it can actually happen, and we knows what to do in this case. This will always appear creating an unit test.

    I always liked checked exceptions, but nowadays I really don’t. You can’t compare forgetting to put a catch block with forgetting to test a return value: the forgotten catch will cause the thread to halt when the exception is raised, which is really great and enough. Checked exceptions will not prevent you from bad code.

  43. Cedric Says:

    Paulo: it’s fine to let *runtime* exceptions bubble all the way to the top. These are programming errors, so they need to 1) abort the program and 2) provide meaningful information for the programmer to diagnose what happened, which is usually done with the stack trace. David Mc Iver just posted an article that goes into more details about this: http://www.drmaciver.com/2010/04/the-best-way-to-handle-exceptions/

    On the other hand, checked exceptions should never be allowed to get that far: they need to be handled and ideally, never crash the program. Which is why it’s so important for checked exceptions to be statically enforced by the compiler.

  44. Elliotte Rusty Harold Says:

    This conversation made me take another look at some Python scripts I use on an almost daily basis (not written by me) and you know what I realized? They are far less robust in practice than the Java code written in the same environment. The Python scripts routinely die with an unhelpful stack trace as a result of bad user input and being run from the wrong directories. They are far too trusting of external data sources; and when they fail they are much less helpful to the end user than Java tools that fail in a similar situation. I strongly suspect the developers who wrote these programs (some in daily use by thousands of people) simply did not pay sufficient attention to error handling. I can’t help but think that if Python used checked exceptions and forced Python programmers to consider the possibility of bad input, then these programs would be more robust. I don’t know if the I/O errors could be corrected in all cases, but at least I wouldn’t see so many hard crashes.

  45. Kaj Kandler Says:

    I can see both sides of the issue. So let me add the things I like about checked exceptions, that are going missing if one uses only RuntimeExceptions:

    * Exceptions tell me what can happen, they are documentation (and documentation that automated tools, like the compiler can work with). If that documentation is going missing (and comment only documentation is not a substitute, because it might not be up to date anymore) I don’t know what to look out for.
    * Exceptions can and should carry the context of the exception, so I can produce messages for humans (internationalized). I.e. the IOException should carry a cause like “no read permission” and the (absolute) path it happened to (if a file).

    If I let unknown runtime exceptions bubble up multiple layers then I have lost context, and a potentially treatable exception becomes untreatable for just that reason.

    This becomes especially important if I write against libraries and APIs. If Exceptions are undocumented, then it is a pain to determine what to handle and how. If they are undocumented and changing over time (new release), how will I be reasonably sure that my program still works with the new version?

    From where I stand neither extreme is a solution. I think we need to document exceptional behavior and make sure it brings with it the context that is needed to understand the specifics of the exception. Error handling is part of programming. So I’d like to see some solution to the dilemma where an Exception is part of the documented API but can be handled more flexible. For example Interfaces could include mechanisms that allow the Interface to catch all exceptions and translate them to a common type or delegate to a specific handler. That way an implementation could throw exceptions that the Interface designer did not foresee (because they are specific to the implementation) and the user of the interface could configure if he wants to deal with the implementation specific things or not.

  46. Ivan Saorin Says:

    I think CHECKED exception is overused in general even at JDK level, but it is not a bad thing. I guess I can deal with JDK. The problem arise from not being clear enough on their use: a not so clear guideline from sun.

    This is my actual strategy.

    RULE #1 – Never, ever rethrow an exception of the same type of the original one. If you are doing this you are probably logging and rethrowing: that is really a bad attitude.

    RULE #2 – Never catch a superclass of a given Exception. The reason is simple: let’s suppose we have a RootException and a WrongBalanceException that extends the former, we release version one of the library to the masses. Eventually some of the users will catch RootException. Now we will introduce a brand new FileValidationFailedException. You can see how the old client code could catch even the new exception without evidence: it should not compile at all as the semantic of the new exception could be totally different.

    RULE #3 – Your application must have some “low level” code: the code that interacts with jdk and thirdy party libraries. Here the checked exception is the way to go. catch what make sense and wrap other conditions around RuntimeExceptions wrappers. You will end up having managed the exceptions or having them wrapped: either case are good. There is one notable “exception” to this: the one or two missing cases in which your “high level” code need to know and do something different in that case wrap the low level exception inside your own HighLevel checked exception.

    RULE #4 – Your wrapper shoud do a kindness to the world and accept two different messages: one is for the end user and one is for the log file. The first is i18n while the latter is in english. Even if your locale is english this make sense: never show to the end user information that should be logged and viceversa.

    The sad thing here is that even following the above rules in your project you will end up with some newbie following every possible antipattern ;)

    What do you think about the rules? They seems to do a good job inside a quite big project.

  47. The exceptions, they come from the future – they all come from the future! « The Subclass Explosion Says:

    […] why is really hard, or so it seems. It must be, since so many have tried and still it hasn’t sunk […]

  48. Kjetil Valstadsve Says:

    Seems like my blog on exceptions from the future got automatically tracked here. It’s a bit stream-of-consciousness, but my main point is that you can’t predict the future. Java, on the other hand, is effectively handing out future prediction wands to everybody, and suggesting that their usage is mandatory. Obviously, there were good intentions to make Java software generally robust, but 15 years later I can’t really see that checked-ness of exceptions have contributed to solid facts on the ground here. Rather, I think the exception mechanism in itself isn’t being used effectively, maybe because the compiler support has given us a false sense of security. Lots of efforts have gone into “handling” exceptions that will never occur, and lots of actual errors have gone unhandled because neither the compiler, nor anyone else, could have predicted the exceptions BY TYPE.

    I’ve been to Elliottes blog before and labored this point. I won’t spend so much effort here this time :-)

  49. Egor Says:

    For me a good advice was: “create your app in some scripting language as a prototype, then convert it into type-safe language”. For scripting language I’ve chosen BeanShell because its syntax is very close to Java. With BeanShell I generally get much faster to something that works, and it’s a joy! A lot of information about types as well as about exceptions is generally missing in this prototype. But then comes a moment when this script becomes rather big and you cannot modify it easily and starting to miss for Eclipse environment with a lot of structure and documentation information. And converting these BeanShell scripts into valid Java programs is so easy in Eclipse with it’s quick assist tools! And now you have to think more about the interface than about the actual implementation. And putting proper JavaDocs, and indicating appropriate exceptions.

    So, for me writing programs is most pleasant with this 2-pass approach:
    – first creating the prototype, no need to think about the exceptions and lot of other things
    – and then create a Java program with exceptions properly declared.

  50. Pedro Newsletter 23-26.04.2010 « Pragmatic Programmer Issues – pietrowski.info Says:

    […] about exception usage and one more, but I’m still against checked […]

  51. Sajal Dutta Says:

    The more unwanted/unexpected situations I can catch, the better! At least the program can have a graceful termination. It’s healthy from the end user perspective. PERIOD.

  52. Julian T Says:

    Interesting thread! One thing I’d add is that that checked exceptions sometimes don’t sit well with inexperienced and/or lazy coders who are using modern IDEs.

    I’ve come across a number of cases like this: the coder writes a line, the IDE underlines it with a red squiggle to tell the coder that an exception needs to be handled. Coder clicks on the helpful little lightbulb in the sidebar, IDE surrounds the code with try/catch and… bingo! The error goes away, but there’s nothing in the catch (maybe a log message if you’re lucky), and you have a swallowed exception.

    If I had a pound/dollar/euro for every time I’ve seen that in the last couple of years, I’d be able to buy myself a reasonable lunch. At least with runtime exceptions people don’t try to catch them and they end up crashing something…

    (Incidentally, does anyone know of any other languages that have implemented checked exceptions? I’d be interested to know…)

    jt

  53. Varun Chopra Says:

    Squirrelsewer Says:
    April 20th, 2010 at 6:39 pm
    For all of the checked exception fans: can you give us some idea of which Exceptions you commonly catch and handle? What % of checked exceptions are you able to handle?

    I agree with Squirrelsewer. Any code examples by Checked exception fans will be important for programmers to understand their point. Just repeating that programmers can handle errors and take alternate actions is not enough. Why so uncommon are the programmers taking alternate actions and what are they doing apart from logging or displaying error to the user?

  54. Eric S Says:

    People continue to repeat Anders’ comment about checked exceptions not scaling, though Gosling debunked this way back in 2003. I’ve worked on large Java systems and never seen this problem either. It only happens if programmers are using exceptions incorrectly, by passing all exceptions up to some top level by sticking them on the throws class without regard for whether they are exposing implemention details.

    Here’s the Gosling interview: http://www.artima.com/intv/solidP.html It’s funny, in this same article, he pretty much covered everything that has just been discussed here. There’s nothing new here. Why do we have to keep having this same argument? Personally I blame it on Java not having come with clear enough instructions about how to use exceptions properly; the arguments and explanations appeared after usage in the wild was already all over the place, and the seeds of confusion implanted in the culture.

  55. Eddie Says:

    @Bruce Eckel, your discussion of “the culture of Java” discusses the supporters of Java as if they are fundamentally different from the supporters of any other language or framework. :) Unless by “the culture of Java” you specifically and narrowly refer to the culture of Sun (now Oracle) and you’re referring only to the architects, designers and implementers of the language itself. I thought I had seen some very clear discussions from folks at Sun in years past recognizing the errors made in AWT and the early collection classes, specifically. I have yet to run into a Java programmer who maintains that Java is absolutely perfect, with no problems or irritations. Anyway, I have yet to find any computer language that perfectly strikes the balance between all of the various tensions pulling on a computer language: ease of development, ease of support, simplicity, code bugs being caught early due to language features, etc. Have you? IMHO, there is no perfect balance.

    @others:

    Ultimately, you can write stable and reliable code in any language, even assembly, even shell script. The question is: “How much work is it?” How hard is it to find and fix the 1000 hour bugs? To what degree does the language or its toolkit or libraries help prevent the introduction of bugs? What happens when you swap 3rd party components with a newer version or different implementation?

    I lean on the side of “checked exceptions are a very good feature and have helped me write more robust code.” That said, I won’t argue that Java has a perfect implementation of them. When coding in Java vs C#, I have a *much* clearer picture of what can go wrong with a Java library, simply by examining the Exceptions that are thrown. I think that Anders’ argument about checked Exceptions not scaling is only true if you refuse to wrap checked Exceptions in other (checked or unchecked) Exceptions. Which is a silly choice to make. Wrapping exceptions is an essential part of maintaining an abstraction. You really don’t care, given an interface, that it can fail with this low level Exception or that one. But you do need to know which methods can fail by throwing an Exception. You will either know this because the language enforces it or through experience of the program failing when an uncaught exception is thrown. Which of those is preferable depends on many things, including the cost of failure, the cost of doing it right the first time, your unit test coverage, the documentation thoroughness of the 3rd party library, and so on.

    Why have other languages not implement Java checked exceptions? I think the choice of everything being unchecked is inferior and lazier and yet much easier to choose. I think the better choice — superior to both — hasn’t been implemented in a language yet. Checked exceptions, IMHO, are the superior choice of those two choices, but they come with a lot of baggage in their current implementation and are maybe not appropriate to all choices. This is why there are so many different kinds of languages out there in common use.

    Maybe what is needed is a method of automatically wrapping exceptions to match the current software layer, so a method could declare that any thrown exception that is not handled is automatically transformed into a different type appropriate to this layer of the abstraction. I agree with others who say, “Saying the *best* choice out of all options is that all exceptions are unchecked exceptions is like saying error checking code is not that important.” It is true that error checking code can add a big clutter to the code. But does that mean it’s better to go without it?

    Those who say that it’s best to catch Exceptions only at the top event loop … clearly don’t work on big enough systems, or at least they work on systems where it’s always OK to throw away a bad event or request. There are certainly realms where that is true enough. It is most definitely not true everywhere. It does not strike me as a surprise that where Java succeeded was at the enterprise level, not at the desktop or web level. I commonly have a try/catch around main event loop as a precautionary measure. I also commonly install an “uncaught exception handler” that logs so that I will always know about uncaught exceptions in 3rd party code. But this is defensive programming, not the solution.

    I think the ultimate solution to checked/unchecked will be found in some new language that will basically choose Java style checked + unchecked exceptions but with a significantly different twist, including a lot of syntactic sugar to solve the many valid points people have brought up about how annoying it can be to handle checked Exceptions. Things such as:

    1) Automatic exception wrapping so exceptions you don’t want to handle can bubble up without being exposed as the base exception they are. If you are a security 3rd party library and you fail because your configuration caused you to throw a MalformedURLException, you want to throw a SecurityConfigurationException that wraps the other so the programmer making use of your library has a proper abstraction.
    1a) Maybe something like try {} catch {} finally {} rethrows XXX where any Exception not explicitly caught is automatically wrapped as XXX, which can itself be checked or unchecked. Then you declare that this method throws XXX, and not whatever set of Exceptions could be wrapped by it, from that code block.
    2) Interface versioning so you can change an interface, changing what Exceptions are or are not declared to be thrown, with ways of handling mismatching interface versions. Maybe automatic wrapping can solve this problem.
    3) Perhaps the ability to mark a given Exception instance as checked or unchecked in a method’s declaration or code, so you can declaratively note whether something is expected to be caught or not. Maybe an annotation.
    4) More things. :)

    I disagree with many of Java’s choices with regards to what is a checked exception and what is not, and in both directions. I find, for example, that my code is more stable when I catch NumberFormatException, as this is almost always NOT a programming bug, but a bad input that needs to be handled. And I have found it appropriate in a very small number of places to catch Throwable, even if to log and rethrow, which as a general practice is not great but in the right place can provide invaluable information if you cannot depend on other software layers to report things appropriately. Also, “software should die on an Error being thrown” is not always true. If you get an out of memory error because the current request requires you to allocate an object that is too big to fit in memory, then you fail that request but don’t crash the program which is otherwise (in my experience) handling things just fine. It just got an invalid request. This depends on context and on whether or not one failed request means others can continue. How independent are the requests coming in? A programmer knows. An language runtime does not.

  56. Peca Says:

    The fact that this language feature has being discussed at such great length and with such opposing arguments, 15 years after its introduction, to me is an indication of a bad design choice. If the Java community is still struggling to properly understand the intent and proper usage of a feature, it should not have made the specification.

  57. dog Says:

    Peca’s argument is the only valid argument I’ve ever heard against checked exceptions. Bruce’s and others come from a habit of bad usage. As explained above there’s no reason your exception lists should grow or you should get leaky abstractions w/checked exceptions. In my over 12 years of Java I’ve had that problem. So I’m with Elliote here. But it is a regret that a lot of developers haven’t figured out how to properly take advantage of them. But I believe that is because most devs are lazy and rather not deal w/errors (which is the whole reason checked exceptions came to exist to start with).

  58. Rupert Frederick Says:

    Reading these comments hurts my brain. Those arguing against checked exceptions are arguing *for* bad API design. Failure modes *ARE PART OF YOUR API*. If your code can fail in a new way that was not anticipated by its API clients, then *YOU’VE BROKEN YOUR API*.

    Those arguing that you are “forced to catch exceptions you can’t handle” are arguing *for* being lazy bastards. You either declare that your method throws that exception (your IDE will do this for you!), or you spend the necessary time figuring out how what you’re calling can fail, and how that will affect your callers. Simply punting on that work because “it’s hard, waaaah” means that you have ill-defined API semantics because you’re just punting random errors to your callers.

    The way to use checked exceptions without a headache is easy:

    – Define a single abstract exception superclass for each subsystem.
    – Declare ‘throws’ using concrete subclasses, and DEFINE under what circumstances those subclasses will be thrown.
    – Translate underlying component’s exceptions into your component’s exception class when letting exceptions bubble out of your component.

    Period. That’s it. Your APIs will be stable, you can add new exceptions to your throw clauses, and you will have well-defined and easy to understand invariants on how, when, and why your APIs can fail.

    Ugh. People against checked-exceptions are just plain lazy bastards and their resultingly ugly code makes me angry. HULK SMASH.

  59. Chris L Says:

    Sorry, had to necro this mind-numbing thread.

    I honestly have no idea what kind of applications folks in the vehemently “pro checked exceptions” camp have worked on, but out here in the server-side development world they just don’t make any sense.

    As Rod Johnson (the godfather of Spring) and many other smart people realized a while back, the notion that you can actually recover from almost any checked exception is ludicrous. Your web app throws an exception while parsing, database access, I/O… guess what? The exception just gets logged, the client is notified, and you move on. That’s it. I’d love to hear some of the convoluted “recovery” scenarios these checked exception guys fantasize.

    So what your left with then is an app that either uses a framework (like Spring) that provides a rich unchecked exception hierarchy, you deal with service methods that throw 14 random things like ParseException because it’s thrown by some underlying dependency, or you cleverly “handle” your SQLException by, ummm, manually catching it and manually logging it right there.

    A robust hierarchy of well-documented RuntimeExceptions are perfect, because they allow you to catch the rare exception you may actually want to do something with, but disregard exceptions flowing through to the server boundary for logging 99.99% of the rest of the time. Honestly, it’d be a huge step forward for the Java API if they’d just simply make all exceptions unchecked (keeping the throws clauses intact on each interface for self-documentation). Adults are then free to choose.

Leave a Reply