« Apple Surrenders
The Next MacBook »

Internal and External Exceptions

Perhaps the continuing confusion over the difference between checked and runtime exceptions in Java is because we haven’t named them properly. Mosts texts and teachers, including myself, have traditionally focused on how and when you handle the exceptions (compile time or runtime) rather than on what causes each. I propose a modification, not in code, but in terminology and teaching. Specifically I think we should should start calling checked exceptions “external exceptions” and runtime exceptions “internal exceptions”.

The idea is this: a checked exception is a response to some external event the program does not have control over. Examples include:

  • File not found (FileNotFoundException)
  • Network socket closed midstream (SocketException)
  • Port already in use (BindException)
  • Malformed XML document (SAXParseException)
  • Database refuses request (SQLException)
  • Bad request or response from a different program (RMIException, JMSException, etc.)

Any exception caused by occurrences outside the program itself should be a checked exception.

By contrast, a runtime exception is caused by a mistake inside the program. Examples include:

  • Precondition violations (IllegalArgumentException)
  • Dereferencing null (NullPointerException)
  • Objects of the wrong type (ClassCastException)
  • Accessing outside an array (IndexOutOfBoundsException)
  • Inserting an object in a read-only collection (UnsupportedOperationException)

These should all be runtime exceptions.

When choosing between checked and runtime exceptions, simply ask yourself where the bug lies. Is the problem that causes the exception inside the program or outside it? If it’s inside, use a runtime exception. If it’s outside, use a checked exception. Simple, easy to understand, and easy to teach. And a lot clearer than complicated verbiage like

checked exceptions are for unpredictable environmental conditions such as I/O errors and XML well-formedness violations while unchecked exceptions are for program failures that should be caught during testing, such as array index out of bounds or null pointers. A checked exception usually cannot be avoided by changing your code while an unchecked exception usually can be. That is, an unchecked exception normally indicates a bug in your program, and a checked exception doesn’t.

This is especially true when you’re teaching undergrads who don’t do any testing at all, and thus for whom the distinction between bugs caught in testing and bugs caught at compile time is non-existent. I’m hopeful that it will be easier to teach them the difference between internal and external causes than the difference between bugs caught at compile time and bugs caught at runtime.

There are some borderline cases. The classic one is a user entering a string which is then converted to an int. For example,

int getNumberFromUser(TextField tf) {
    String s = tf.getText();
    return Integer.parseInt(s);
}

If the user enters a non-numeric value, getNumberFromUser throws a NumberFormatException, a runtime exception. How do we account for this?

I think we can do that by breaking this into two parts. From the perspective of the Integer.parseInt() method, a runtime exception is appropriate. The bad string is a precondition violation. An argument was passed that is not according to spec. This argument came from another part of the same program. Integer.parseInt() does not accept input from the user. Therefore, NumberFormatException is rightly a runtime exception.

The mistake here really is in the code that invokes Integer.parseInt(). It should have checked that the value was a correct numeric string before passing it to a different method. It failed to verify the user input. This program is buggy, irrespective of user input. The uncaught runtime exception indicates that.

Now for practical purposes and convenience, we may well wish to allow Integer.parseInt() to do the necessary check anyway. There’s no need to duplicate the code. However, a non-buggy invoking method should catch the runtime exception and convert it to a checked exception. For example,

int getNumberFromUser(TextField tf) throws UserInputException {
    String s = tf.getText();
    try {
        return Integer.parseInt(s);
    }
    catch (NumberFormatException ex) {
        throw new UserInputException(s + " is not a number");
    }
}

...
public class UserInputException extends Exception {

    public UserInputException(String message) {
        super(message);
    }

}

That is, we really need two methods: one that reads a string from the user and returns an integer, and one that reads a a string from another part of the program and returns an integer. The first may call the second, but these are not the same methods, and they do not throw the same exception.

It doesn’t help that a lot of APIs, even some in the core JDK, get this wrong. For example, CloneNotSupportedException always indicates an internal program bug. It really should be a runtime exception (and if it were Cloneable would be quite a bit simpler and easier to implement). In fact, I suspect the JDK might well be improved if we went through all its exception classes and recategorized them according to this scheme. But overall I do think that exceptions are neatly sorted into those caused by internal mistakes and those caused by external data. When you find a checked exception caused by internal bugs or a runtime exception caused by external conditions, chances are very good this indicates a design flaw that should be corrected.

To sum up, here’s the rule:

If the exception is caused by problems internal to the program, it’s a runtime exception. If it’s caused by problems external to the program, it’s a checked exception.

Short, simple, to the point. Are there any exceptions to this rule? Are there any cases where an internal program bug legitimately should be signaled by a checked exception or a problem in the external environment should be signaled by a runtime exception? I can’t think of any. What do you think?

« Apple Surrenders
The Next MacBook »

This entry was posted on Saturday, July 21st, 2007 at 8:26 am and is filed under Java. You can follow any responses to this entry through the Atom feed. You can make a comment, Digg this story, or trackback from your own site.

35 Responses to “Internal and External Exceptions”

  1.   Perhaps not? by Î» Tony’s blog λ Says:
    July 21st, 2007 at 4:02 pm

    […] cafe.elharo.com/java/internal-and-external-exceptions/ Perhaps the continuing confusion over the difference between checked and runtime exceptions in Java […]

  2. Ingo Says:
    July 21st, 2007 at 5:01 pm

    I don’t think it’s important whether the problem was internal or external. The choice has to be with what you can do about it!
    If you can’t deal with it than throw a runtime exceptions. There is no point in bubbling it up and write all the boilerplate code. Likelyhood is that only the outermost layer needs to know to tell the user. In these cases make the app stop what it was doing and let the outer layer tell the user.
    If the calling code can and should deal with the exception than throw a checked exception and force the code calling your method to do so. Personally I actually introduced a compromise exception, the Expected Runtime Exception for exceptions I can handle but not in the calling code but inside the outermost code.

  3. Elliotte Rusty Harold Says:
    July 21st, 2007 at 6:57 pm

    Sorry, no. The decision is most definitely not based on what you can do about it. What you can do about a problem has two consequences:

    • If the program can’t handle the problem at all, then it’s an Error, not an Exception.
    • If the program can’t handle the problem right where it’s detected, then an exception is thrown. If the program can handle the problem immediately, then no exception need be thrown.

    However this has no effect on the choice of whether to throw a checked or a runtime exception.

    It is rarely if ever acceptable for an exception to simply shut down an application and alert the user. (I am assuming we’re discussing production applications here, not student homework.)

    An uncaught runtime exception always indicates a bug in a program. An uncaught checked exception is harder to produce, but still indicates a bug in a program when it does occur. A program that lets an exception bubble up to the VM and the user is buggy.

  4. Ingo Says:
    July 22nd, 2007 at 3:47 am

    There will always be cases we can’t deal with! Database down – external resource not available …
    I do not say bubble up to the VM or let the user see a stack trace etc.
    I say do not bother all the code in between the exception location and the outer layer who can make a sensible decision on how to deal with such instances – which might include telling the user that a fatal exception occurred and to inform the administrator.
    The outer layer will always need to deal with Runtime exceptions, whether they are thrown by our code or by other code we invoked.
    Truth of the matter is that only very rarely the exception should/can be handled in the code who called the code throwing it. Then a checked exception is correct.
    My ExpectedRunttimeException is for the outer layer to decide whether he can give a meaningful response to the client, for example tell him that his record was updated by someone else, or whether it’s something we did not anticipate at all and hence have no meaningful answer waiting for.
    Development of applications, apart from student homework, is about making it work not about getting any academic ideas about Error vs Exception and Checked vs Unchecked right. Making developers place multiple catch clauses in the code in areas where they can’t do anything about it is the reason for the (still inexcusable) habit of people catching Exception and placing empty catch clauses into the code.

  5. Roland Pibinger Says:
    July 22nd, 2007 at 6:04 am

    A similar classification: Contingency vs. Fault
    dev2dev.bea.com/lpt/a/541

  6. Elliotte Rusty Harold Says:
    July 22nd, 2007 at 8:02 am

    Ah. I see. You’ve forgotten that the code that invokes a method that may throw a checked exception does not have to catch the checked exception. The invoking method is always free to simply declare that it itself throws the same exception. This allows the exception to bubble up as many levels as necessary to find the method that can and should handle the problem. Overuse of catch and underuse of throws is a common antipattern in Java code. The wrong solution to this problem is changing the checked exception to a runtime exception. The right solution is adding a throws clause.

  7. Ingo Says:
    July 22nd, 2007 at 8:56 am

    Admittedly less verbose than the catch (especially for multiple exceptions) but still leaving the issue that the code in the middle has to deal with issues it can’t do anything about.
    If I work with existing code that changed to use a method that throws a checked exception, I will now have to change all methods upstream to throw this exception as well. Lastly it still leaves the issue that developers will (I agree wrongly) just deal with it by catching Exception or even far worse swallowing it.

  8. Bob Robertson Says:
    July 23rd, 2007 at 2:28 am

    Good article. Have to mostly agree with Ingo, bsimply adding throws clauses is not always enough either. If your code uses an abstraction then it is not good practice to expose the exceptions that can be thrown from the concrete implementations. For example, if I use an interface Cache that can be implemented with a database or a file-based solution. My interface should not throw IOExceptions and SQLExceptions, and every time I add a new implementation I have to extend the throws clause. So that forces my implementing classes to catch the lower level checked exceptions and convert them into a custom exception at a suitable level of abstraction e.g. CacheException. This quickly gets tedious and results in a large amount of boilerplate code.

    I would, however, refine the idea that the type of exception depends on what you can do with it. When writing a library, or a layer in a large project, it’s very important that you specify the exceptions that can be thrown, so that whoever uses your code doesn’t get nasty surprises. If I work in a smallish team responsible for a complete app, from front to back, then it’s generally much easier to use runtime exceptions.

  9. Norbert Ehreke Says:
    July 23rd, 2007 at 3:30 am

    Your idea begs the question: What exactly is external and what is internal?

    IMHO it depends on the context. In a modularized software system, the definition of external and internal cannot be made at compile-time. What if, in the context that a method is used, the declared exception is actually not a problem at all, but expected behavior? An empty catch clause always leaves a bitter taste, to say the least. And in the opposite case, that it cannot be sensibly handled, you’d say, add a throws clause, right? But, if we keep adding throws clauses to all the higher layered methods, our software will eventually be littered with checked exceptions that make no sense from a more abstract point of view.

    The problem with checked exceptions is still, that they force the user of a method (a developer that uses an API) to deal with problems that are not necessarily part of the problem domain at hand. What if I am absolutely content to handle an unparsable number as null? Sadly, I am still stuck with NumberFormatExceptions, wrapped and unwrapped.

  10. Elliotte Rusty Harold Says:
    July 23rd, 2007 at 4:54 am

    Checked exceptions do not force the user of a method (a developer that uses an API) to deal with problems that are not necessarily part of the problem domain at hand. They force the developer to acknowledge that problems may arise, whether they want them to or not. Changing a checked exception to a runtime exception would not change the fact that an exception is thrown.

    If indeed null is an acceptable response, then a method is free to return null instead of throwing an exception. That’s a call the designer of the method has to make. A method that invokes a method that throws an exception can catch an exception an itself return null, if that makes sense. You are not stuck with anything.

    As we’ve seen time and time again, most recently in this thread, developers like to shift the blame when something goes wrong in their code. They like to blame “user error” because their code can’t handle a typo. They blame hardware failure if the disk fills up while they’re writing. Anything to avoid having to do include necessary error handlers in the code. Exceptions prevent this blame shifting and force developers to write more robust code. This is a good thing.

  11. Halvorsen Says:
    July 23rd, 2007 at 5:13 am

    Wow, did you read my blog entry: www.jroller.com/jaha/entry/the_horror_of_the_checked? :-), I have not always agreed with you, but when we do we realy do! Think we pretty much arrived at the same rule for when go checked and unchecked! I think an important point to remember are:

    The handling if an checked exception (cx) are often litle more than: Preserve valid state and stay alive; its not us that are in error, and maybe it goes away or at least allow human (end user, server administrators) to decide further actions (stay up, terminate as normal as possible).

    But as I said in my blog, I feel the biggest problem with cx are that they in some cases has become sleeping pillows for developers: When throwing unchecked exceptions there must be means for users of that API to avoid making that programming error, easier then to throw cx! See my blog for my SQLException example.

  12. Unilever Centre for Molecular Informatics, Cambridge - Jim Downing » Blog Archive » When and what to throw Says:
    July 23rd, 2007 at 5:18 am

    […] post from Elliotte Harold, proposing a new nomenclature for exceptions, whereby checked exceptions are referred to as “external” and runtime exceptions as […]

  13. Ingo Says:
    July 23rd, 2007 at 5:45 am

    It’s not about shifting the blame. It’s about handling the issue at the point we can!
    If you can handle a full disk – then do. You will however want to deal with it once. The point you where you are able to do so is generally at the root of the call (what I would call the service layer – e.g. the entry-method of the particular call).
    Here you will have to deal with runtime exceptions anyway – even if you do not throw any, other pieces of code will.
    Same as with checked Exceptions you can extend Runtime exception and create yourself a structure that will allow this layer to deal with specific issues specifically.
    What I say is that I do not want to bother all the code in between with these exceptions – checked exceptions force me too!

  14. Norbert Ehreke Says:
    July 23rd, 2007 at 7:14 am

    Thanks Ingo, I wholeheartedly agree. This is not at all about shifting the blame. Eliotte, you did not answer the question: How can you define external and internal at compile-time or even design-time? I do not think you can, without proper a context. Sure, I do see the virtue of transparent code, say, when a method signals potential problems, but this expressiveness results in cumbersome rethrows (or, worse, empty catch clauses). That’s an annoyance at best, a design flaw of Java at worst — in fact, the way that checked exceptions are actually used in real-world applications have resulted in harder-to-debug, less robust(!) code. Do you honestly think that complex systems written in C# are less robust than Java systems? The anti-patterns are rooted within the abilities of the respective development team, not within the language.

  15. Yury Says:
    July 23rd, 2007 at 8:36 am

    Again and again… Why is it do difficult?! “Checked” exception is something to BE ALWAYS checked (Either by catching or by including it into the method declaration). “Unchecked” (Runtime) excepion can be not checked (one is allowed not catching it or including it to the method declaration). Is it not simple? Now the quetsion is which type of exceptions to use in each particular case. There can not be a definitive answer to that! In one case I may decide to report all “external” to my code problems by means of “checked” exceptions. I do that because I hope that the guy calling my code knows better what to do. Or I am pesimistic (or realistic) and I do not believe that anyone can handle those problems (since they are even more far away from the root cause) so I give up and throw runtime exceptions.

  16. Ravi V Says:
    July 23rd, 2007 at 9:44 am

    From the articles on Checked Exceptions published at this site, I understand (probably inaccurately) Elliotte to be saying the following:

    1. Checked Exceptions in Java are wonderful.

    2. If you truly understand Checked Exceptions, they have no problems whatsoever.

    3. If you are having problems using Checked Exceptions then:
    (a) You do not understand the concept of Checked Exceptions or when to use them; or
    (b) You do not realize that a Checked Exception can be included in the throws clause of a method signature, making everything simple according to ERH; or
    (c) You are a lazy developer who likes to pass the buck; or
    (d) You do not like to write “robust” code; or
    (e) All of the above.

    Since ER Harold seems to believe the above very strongly, what is to be gained by any further discussion?

    Let us agree to disagree since I do not think either party can convince the other of the merits of its arguments.

  17. Kjetil Valstadsve Says:
    July 23rd, 2007 at 10:06 am

    Once again I see advice from ERH to simply add the throws clause for any troublesome checked exception. As I asked repeatedly in the predecessor thread: Is it really so that I am recommended to add, say, SQLException, to any and all methods in an interface that is in, say, the domain model layer?

    Sure, you may of course have only one implementation of the domain model interfaces – ever – and yes, they are implemented on top of a database then. But then, ERH is a teacher, and he will probably, rightly, give you sage advice not to expose implementation details needlessly. But, how is re-declaration of SQLException not exposing implementation details? How does it not nudge us towards a monolithic application by introducing dependencies? And how does it not follow that other exceptions deserve the same treatment as SQLException, so that they should get to feature in my interface as well?

    FileNotFoundException? Someone deletes a file in error.

    SocketException? A switch or VPN process dies.

    BindException? Someone starts your program twice.

    SAXParseException? Some external web service bugs out.

    All of these are external. The domain model layer can’t handle them. Should we re-declare them in Account or Person interfaces? Bubble them all up as far as needed to reach the outer exception handling logic, predictably accumulating to mammoth throws lists in “upper” methods, tying their host interfaces to any and all implementation details “below”?

    I suspect not, yet read your advice as “yes”. What’s the deeper insight here? Other than that, at least I can agree that overuse of “catch” is a bad smell spacer Just don’t ask me about “throws”!

  18. Gili Says:
    July 23rd, 2007 at 12:26 pm

    Elliotte nails the definition very well! The book “Effective Java” has a more complete definition, but Elliotte’s definition is a perfect “in a nutshell” explanation of what is going on.

    Most APIs out there are written by people who don’t understand the concept of checked vs unchecked exception which is why the rest of the masses whine and moan about how awful checked exceptions are. If more API developers respected Elliotte’s simple rule we wouldn’t be in this mess 😉

  19. Randy Says:
    July 23rd, 2007 at 4:22 pm

    As someone whose mind can be changed by new data (hopefully we all consider ourselves in that category to some degree), I’m struggling with the following question:

    Don’t I need to catch-wrap-throw things like SQLExceptions to insulate my callers from my implementation regardless of whether the exceptions are checked or unchecked? If so, then the ugliness of the catch-wrap-throw idiom is a problem with both approaches. Maybe something that both camps can use is some syntactic sugar to reduce the idiom’s intrusiveness.

  20. Elliotte Rusty Harold Says:
    July 23rd, 2007 at 6:14 pm

    Kjetil,

    You do not need to rethrow a SQLException from your domain model classes if it’s not appropriate. You may instead choose to catch SQLException and rethrow a more appropriate exception. For example,

    try {
       someDatabaseAccessingMethod();
    }
    catch (SQLExcepiton ex) {
      throw new DomainModelException(ex.getMessage()); 
    }

    In rare cases you might even convert a checked exception to a runtime exception in this fashion (but that’s really only appropriate if you can guarantee from the code that the checked exception will not in fact be thrown. Thus the runtime exception is more like an assert.)

    However what is never appropriate is to simply ignore the problem. If there can be a SQLException, then you will need to deal with it somehow, somewhere. You can’t just sweep it under the rug.

  21. Nick Says:
    July 23rd, 2007 at 6:35 pm

    Gili,
    Bloch’s guidelines in “Effective Java” are actually much closer to Ingo’s. Item 40 states “Use checked exceptions for recoverable conditions and run-time exceptions for programming errors”. He then expounds on this in item 41 where he states “The burden (of checked exceptions) is justified if the exceptional condition cannot be prevented by proper use of the API and the programmer using the API can take some useful action once confronted with the exception.

    Elliotte:
    A few years ago (when I was still in academia land) I would have agreed with you. However, after several years of working on real-life software applications (or corrupted by real-life software applications, if you prefer spacer ), I have to disagree. Throwing checked exceptions when you can’t expect the calling method to do anything about it violates the principle of encapsulation, as you are forcing the calling method to deal with something it frankly doesn’t care about. And as far as adding throws clauses goes, that doesn’t end up working very well either as your throws clauses will grow exponentially. If you write a method which calls two other methods that throw checked exceptions, it will be forced to throw them both (assuming it cannot do anything about them). And then if that method’s parent calls both it and a sister method that also throws two checked exceptions, it will be forced to throw 4. Then if that method’s caller calls both it another method that throws 4 exceptions, well you get the picture. And add to all that, your top level method has now become tightly coupled to all the underlying methods that have thrown something it is now catching.

    Yeah, with unchecked exceptions the top level code will have to catch a base Exception and post some generic error message (and log the details), but thats usually all the user will need. It sure beats having the top level code deal with every single error condition the underlying code could possibly hit individually.

  22. Straw Man Says:
    July 23rd, 2007 at 8:29 pm

    >The right solution is adding a throws clause.

    I agree 100% Adding a throws clause is very elegant & easy – be lazy!. I prefer a throws clause to try/catch blocks. Try/catch blocks are very often uneccesary and ugly.

    >doesn’t end up working very well either as your throws clauses grows exponentially.
    >…Then if that method’s caller calls both it another method that throws 4 exceptions, well you get the picture.

    Yes a picture that looks a little like a straw man. Wrap those exceptions silly.

  23. Nick Says:
    July 23rd, 2007 at 9:03 pm

    StrawMan,

    Wrapping exceptions requires handling the exceptions, which is precisely what he was trying to avoid when he suggested adding throws clauses. So no strawman, just a demonstration of the flaw in the given suggestion. And furthermore, wrapping exceptions have problems in that you often lose the original exception that caused the problem in the first place. You know, the interesting one.

    Again, throwing checked exceptions that the calling method cannot be expected to handle is an unfortunately common antipattern in software development. Remember, you are always free to declare or catch an unchecked exception. You are never free to ignore a checked exception.

  24. Ingo Says:
    July 24th, 2007 at 2:15 am

    Elliot, on the academic side you are most probably right in respect to checked vs unchecked (I’m not so sure regarding internal vs external). When checked exceptions where introduced into Java the idea was to force people to use and to handle these to make sure people did not ignore them. Reality however showed that people who do not care about good exception handling will find ways around it – shortcuts that made it worse, not better. If you look into real code you’ll find empty catches and areas catching or throwing just exception.
    Throwing unchecked exceptions doesn’t make it worse nor better. You are still free to cheat and avoid dealing with them and you are still free to handle and deal with them.
    You do however make it easier to deal with them collectively in one area and avoid having to deal (if only to re-throw or wrap) with them in multiple areas – each one an area where someone can deal with them wrongly.
    At the end it comes back to the question of what’s more important – academic correctness or pragmatism.
    Personally I believe the later to be more important, which is the main theme of my blog (Golden Toolbox. Sorry for the shameless plug – however there are a couple of posts where you now have the chance to critique me :-).

  25. Elliotte Rusty Harold Says:
    July 24th, 2007 at 6:04 am

    I do not agree that throwing checked exceptions that the calling method cannot be expected to handle is an antipattern. The throwing method in general knows nothing about what the calling method can or cannot handle. Some methods that call it may be able to handle the exception. Others may not, and have to rethrow it. Regardless, the throwing method never expects that the calling method can handle the exception and the throwing method never expects that the calling method can’t handle the exception. Its job is to notify the calling method of the exception, not to worry about how the calling method will or will not handle it.

    I’ll have to reread Bloch, but I think what he meant was not whether the calling method could be expected to handle it, but whether any method in the call chain could (and if he didn’t mean that, he should have). There are cases such as OutOfMemoryError that really can’t be handled properly 90% of the time. These are represented by errors, not exceptions (either checked or runtime) and they’re very uncommon.

gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.