528

For a number of years now I have been unable to get a decent answer to the following question: why are some developers so against checked exceptions? I have had numerous conversations, read things on blogs, read what Bruce Eckel had to say (the first person I saw speak out against them).

I am currently writing some new code and paying very careful attention to how I deal with exceptions. I am trying to see the point of view of the "we don't like checked exceptions" crowd and I still cannot see it.

Every conversation I have ends with the same question going unanswered... let me set it up:

In general (from how Java was designed),

  • Error is for things that should never be caught (VM has a peanut allergy and someone dropped a jar of peanuts on it)
  • RuntimeException is for things that the programmer did wrong (programmer walked off the end of an array)
  • Exception (except RuntimeException) is for things that are out of the programmer's control (disk fills up while writing to the file system, file handle limit for the process has been reached and you cannot open any more files)
  • Throwable is simply the parent of all of the exception types.

A common argument I hear is that if an exception happens then all the developer is going to do is exit the program.

Another common argument I hear is that checked exceptions make it harder to refactor code.

For the "all I am going to do is exit" argument I say that even if you are exiting you need to display a reasonable error message. If you are just punting on handling errors then your users won't be overly happy when the program exits without a clear indication of why.

For the "it makes it hard to refactor" crowd, that indicates that the proper level of abstraction wasn't chosen. Rather than declare a method throws an IOException, the IOException should be transformed into an exception that is more suited for what is going on.

I don't have an issue with wrapping Main with catch(Exception) (or in some cases catch(Throwable) to ensure that the program can exit gracefully - but I always catch the specific exceptions I need to. Doing that allows me to, at the very least, display an appropriate error message.

The question that people never reply to is this:

If you throw RuntimeException subclasses instead of Exception subclasses then how do you know what you are supposed to catch?

If the answer is catch Exception then you are also dealing with programmer errors the same way as system exceptions. That seems wrong to me.

If you catch Throwable then you are treating system exceptions and VM errors (and the like) the same way. That seems wrong to me.

If the answer is that you catch only the exceptions you know are thrown then how do you know what ones are thrown? What happens when programmer X throws a new exception and forgot to catch it? That seems very dangerous to me.

I would say that a program that displays a stack trace is wrong. Do people who don't like checked exceptions not feel that way?

So, if you don't like checked exceptions can you explain why not AND answer the question that doesn't get answered please?

I am not looking for advice on when to use either model, what I am looking for is why people extend from RuntimeException because they don't like extending from Exception and/or why they catch an exception and then rethrow a RuntimeException rather than add throws to their method. I want to understand the motivation for disliking checked exceptions.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
TofuBeer
  • 60,850
  • 18
  • 118
  • 163
  • 49
    I don't think it's completely subjective - it's a language feature that was designed to have a specific use, rather than for everyone to decide what it's for for themselves. And it's not especially argumentative, it addresses in advance specific rebuttals which people could easily have come up with. – Gareth Mar 05 '09 at 08:49
  • 8
    Come on. Viewed as a language feature, this topic has been and can be approached in an objective way. – Kurt Schelfthout Mar 05 '09 at 12:30
  • 6
    @cletus "answering your own question" if I had the answer I wouldn't have asked the question! – TofuBeer Mar 05 '09 at 15:32
  • 2
    I agree that it should be CW. There is no "right" answer; it's about methodology and practices. I don't agree that it should be closed, however. It's an important debate, and the more opinions can be seen on the subject, the better, IMO. – Randolpho Mar 05 '09 at 16:48
  • 2
    I am not asking for the "right answer about methodology and practices" I am asking for the rationale for people who choose this particular methodology. I did not ask for the relative merits between different ways of dealing with exceptions. Also not CW IMO, that is for a comparison between the two – TofuBeer Mar 05 '09 at 17:01
  • 9
    Great question. In C++ there are no checked exceptions at all, and in my opinion it renders the exception feature unusable. You end up in a situation where you have to put a catch around every single function call you make, because you just don't know whether it might throw something. – Dimitri C. Jun 24 '09 at 10:15
  • 2
    @TofuBeer: you are *way* overthinking this: ask yourself the following question: where do checked exception come into play at the OOA/OOD level and how comes, what, 95% of the languages out there are perfectly happy without the broken concept of checked exceptions? Checked exceptions are a Java idiosynchrasy that people have to deal with because there are broken API that have been written around that broken concept. 200KLOC codebase here. We defined *zero* checked exception and we're throwing *zero* checked exception. And our OOP is close to our OOA/OOD. That's why we don't like them. – SyntaxT3rr0r Mar 18 '10 at 18:32
  • 3
    C++ is broken without checked exceptions IMO - how often do you see catch(...) just to make sure things do not crash. So, since you have a large code base, please answer the simple question - how do you make sure that you do not miss any exceptions? Say you add in a new "FooException" - how do you ensure that your program doesn't crash if you fail to catch it? How do you catch it in all of the correct places? – TofuBeer Mar 18 '10 at 20:19
  • 1
    usign TDD and rutime exceptions resolves the problem with checked exception (if one afraids that he can miss something). but unfortunately java core libs themself force you to catch those exception, that makes your code bigger, often without reason. I think using AOP/spring can handle some problem as well - kind of something on top on java. – ses May 10 '13 at 14:16
  • 2
    @ses TDD doesn't solve the problem unless one looks at all of the source code to to know what to test for. It works for the person writing the code that throws the RuntimeException, but not for the person writing the code that calls the code that throws it. Start with the premise that your program cannot crash, ever, now how attractive are RuntimeExceptions? – TofuBeer May 10 '13 at 14:20
  • @TofuBeer The person who writes the code, does not know for sure that person(client) who would use this code should check this exception. because it depends on the case what client thinks about it. The client itself can decide, reading the definition of method that throws RuntimeException where he want to catch it or not. That's fair. That's respect of client's time and clinet's code. Especially I do not see the reason to use CheckedExceptions in interface methods, when 1000 of classes implement it, in 500 of them don't throw this exception at all, but the client still must catch it. – ses May 10 '13 at 14:36
  • @TofuBeer if client of code uses TDD, it helps him to avoid bad cases. – ses May 10 '13 at 14:36
  • 2
    @ses the client won't necessarily know about the runtime exception, there is no requirement that runtime exceptions be documented. If the client doesn't know how can the client make an informed decision? Also, my premise is that the program can never crash. runtime exceptions do not lend themselves to that. – TofuBeer May 10 '13 at 14:42
  • @TofuBeer also Client might not to know how to handle it. This is what happened all the time. The client just swallows it until he has a problem. So client _should_ know about exception / and about what he is going to use - and about what the method does. As soon as he knows about it he could decide what to do with that. – ses May 10 '13 at 15:27
  • 2
    And the client will know about the exception how exactly? Follow it through to the logical conclusion. I give you library X, you call method y from class Z. What runtime exceptions should you catch? – TofuBeer May 10 '13 at 16:16
  • I personally like checked exceptions very much, these help me to recognize potential problems in my code very early. But one thing I hate about it is that the throws declaration is also a part of function signatures. This can really get you in a problem with no solution at all. Thats the thing I think most programmers don't like. – Aqeel Ashiq Sep 23 '13 at 09:06
  • By reading its contract? Exceptions are part of a methods contract, checked or not. You catch the exceptions you can actually do something about. – Kevin Aug 05 '15 at 00:41
  • 2
    That is the issue @Kevin, if you add a 3rd party library that doesn't document the exceptions then what? The whole point of checked exceptions is to avoid programmer mistakes... using unchecked exceptions for things that should be dealt with (things that are not programmer errors) negates that. – TofuBeer Aug 06 '15 at 07:12
  • @TofuBeer Even if you are using checked exceptions, if you don't document exceptions (outside of the method header itself) and under what specific conditions they occur, they wouldn't know how to deal with your exceptions either. The problem isn't checked vs unchecked exceptions, but one of documentation. – Kevin Aug 06 '15 at 13:07
  • 3
    Checked exceptions encourage documentation, and, in the event they are not documented they are still known about. Unchecked exceptions can more easily not be documented and, worse, not be known about until they happen in a production environment. – TofuBeer Aug 13 '15 at 02:55
  • @DimitriC. That is how I feel as a C# developer now! – Honinbo Shusaku Mar 29 '17 at 19:42
  • "VM has a peanut allergy and someone dropped a jar of peanuts on it" - Yup, you definitely want your machine to die without the possibility of recovery at the most critical moments... I don't see anything wrong with that.. NEVER USE ERROR – B T Jun 07 '17 at 00:29
  • It seems nobody noticed the problem with interfaces. If you implement an interface, you can only throw the exceptions that are declared in the interface. Making it impossible to react to an error with checked exception in many different cases. See my answer. – Vlasec Oct 09 '17 at 14:44
  • 6
    The strongest argument I know *for* checked exceptions is that they weren't originally there in Java, and that when they were introduced they discovered hundreds of bugs in the JDK. This is somewhat prior to Java 1.0. I personally would not be without them, and disagree violently with Bruce Eckel and others on this. – user207421 Apr 12 '19 at 02:16
  • 1
    @user207421 in my experience, most anything Bruce Eckel says is wrong when it comes to Java... – jwenting Jan 08 '20 at 11:02
  • 1
    This is the question. Many libraries don't throw checked exceptions, so the programmer is not aware of everything that can go wrong and prepare for it. Unless he/she reads the source code, but who reads any kind of documentation? Unless they test really carefully, but who crafts tests like they are a very important thing? To both questions I guess the answer is only a few. – Jorge Viana May 23 '20 at 14:33
  • There are some methods I have to call that throw certain exceptions that I **KNOW** will **NEVER** happen because of the params I pass. Those are okay to catch and ignore. – Captain Jack Sparrow Mar 03 '22 at 17:04
  • Language and library authors "assume" that programmer will "always" want to handle a particular type of error, and that too "immediately". Totally wrong assumptions given the infinite ways real world programmers actually use exceptions. – S.D. Jun 02 '23 at 16:10

33 Answers33

325

I think I read the same Bruce Eckel interview that you did - and it's always bugged me. In fact, the argument was made by the interviewee (if this is indeed the post you're talking about) Anders Hejlsberg, the MS genius behind .NET and C#.

http://www.artima.com/intv/handcuffs.html

Fan though I am of Hejlsberg and his work, this argument has always struck me as bogus. It basically boils down to:

"Checked exceptions are bad because programmers just abuse them by always catching them and dismissing them which leads to problems being hidden and ignored that would otherwise be presented to the user".

By "otherwise presented to the user" I mean if you use a runtime exception the lazy programmer will just ignore it (versus catching it with an empty catch block) and the user will see it.

The summary of the argument is that "Programmers won't use them properly and not using them properly is worse than not having them".

There is some truth to this argument and in fact, I suspect Goslings motivation for not putting operator overrides in Java comes from a similar argument - they confuse the programmer because they are often abused.

But in the end, I find it a bogus argument of Hejlsberg's and possibly a post-hoc one created to explain the lack rather than a well thought out decision.

I would argue that while the over-use of checked exceptions is a bad thing and tends to lead to sloppy handling by users, but the proper use of them allows the API programmer to give great benefit to the API client programmer.

Now the API programmer has to be careful not to throw checked exceptions all over the place, or they will simply annoy the client programmer. The very lazy client programmer will resort to catch (Exception) {} as Hejlsberg warns and all benefit will be lost and hell will ensue. But in some circumstances, there's just no substitute for a good checked exception.

For me, the classic example is the file-open API. Every programming language in the history of languages (on file systems at least) has an API somewhere that lets you open a file. And every client programmer using this API knows that they have to deal with the case that the file they are trying to open doesn't exist. Let me rephrase that: Every client programmer using this API should know that they have to deal with this case. And there's the rub: can the API programmer help them know they should deal with it through commenting alone or can they indeed insist the client deal with it.

In C the idiom goes something like

  if (f = fopen("goodluckfindingthisfile")) { ... } 
  else { // file not found ...

where fopen indicates failure by returning 0 and C (foolishly) lets you treat 0 as a boolean and... Basically, you learn this idiom and you're okay. But what if you're a noob and you didn't learn the idiom. Then, of course, you start out with

   f = fopen("goodluckfindingthisfile");
   f.read(); // BANG! 

and learn the hard way.

Note that we're only talking about strongly typed languages here: There's a clear idea of what an API is in a strongly typed language: It's a smorgasbord of functionality (methods) for you to use with a clearly defined protocol for each one.

That clearly defined protocol is typically defined by a method signature. Here fopen requires that you pass it a string (or a char* in the case of C). If you give it something else you get a compile-time error. You didn't follow the protocol - you're not using the API properly.

In some (obscure) languages the return type is part of the protocol too. If you try to call the equivalent of fopen() in some languages without assigning it to a variable you'll also get a compile-time error (you can only do that with void functions).

The point I'm trying to make is that: In a statically typed language the API programmer encourages the client to use the API properly by preventing their client code from compiling if it makes any obvious mistakes.

(In a dynamically typed language, like Ruby, you can pass anything, say a float, as the file name - and it will compile. Why hassle the user with checked exceptions if you're not even going to control the method arguments. The arguments made here apply to statically-typed languages only.)

So, what about checked exceptions?

Well here's one of the Java APIs you can use for opening a file.

try {
  f = new FileInputStream("goodluckfindingthisfile");
}
catch (FileNotFoundException e) {
  // deal with it. No really, deal with it!
  ... // this is me dealing with it
}

See that catch? Here's the signature for that API method:

public FileInputStream(String name)
                throws FileNotFoundException

Note that FileNotFoundException is a checked exception.

The API programmer is saying this to you: "You may use this constructor to create a new FileInputStream but you

a) must pass in the file name as a String
b) must accept the possibility that the file might not be found at runtime"

And that's the whole point as far as I'm concerned.

The key is basically what the question states as "Things that are out of the programmer's control". My first thought was that he/she means things that are out of the API programmers control. But in fact, checked exceptions when used properly should really be for things that are out of both the client programmer's and the API programmer's control. I think this is the key to not abusing checked exceptions.

I think the file-open illustrates the point nicely. The API programmer knows you might give them a file name that turns out to be nonexistent at the time the API is called, and that they won't be able to return you what you wanted, but will have to throw an exception. They also know that this will happen pretty regularly and that the client programmer might expect the file name to be correct at the time they wrote the call, but it might be wrong at runtime for reasons beyond their control too.

So the API makes it explicit: There will be cases where this file doesn't exist at the time you call me and you had damn well better deal with it.

This would be clearer with a counter-case. Imagine I'm writing a table API. I have the table model somewhere with an API including this method:

public RowData getRowData(int row) 

Now as an API programmer I know there will be cases where some client passes in a negative value for the row or a row value outside of the table. So I might be tempted to throw a checked exception and force the client to deal with it:

public RowData getRowData(int row) throws CheckedInvalidRowNumberException

(I wouldn't really call it "Checked" of course.)

This is bad use of checked exceptions. The client code is going to be full of calls to fetch row data, every one of which is going to have to use a try/catch, and for what? Are they going to report to the user that the wrong row was sought? Probably not - because whatever the UI surrounding my table view is, it shouldn't let the user get into a state where an illegal row is being requested. So it's a bug on the part of the client programmer.

The API programmer can still predict that the client will code such bugs and should handle it with a runtime exception like an IllegalArgumentException.

With a checked exception in getRowData, this is clearly a case that's going to lead to Hejlsberg's lazy programmer simply adding empty catches. When that happens, the illegal row values will not be obvious even to the tester or the client developer debugging, rather they'll lead to knock-on errors that are hard to pinpoint the source of. Arianne rockets will blow up after launch.

Okay, so here's the problem: I'm saying that the checked exception FileNotFoundException is not just a good thing but an essential tool in the API programmers toolbox for defining the API in the most useful way for the client programmer. But the CheckedInvalidRowNumberException is a big inconvenience, leading to bad programming and should be avoided. But how to tell the difference.

I guess it's not an exact science and I guess that underlies and perhaps justifies to a certain extent Hejlsberg's argument. But I'm not happy throwing the baby out with the bathwater here, so allow me to extract some rules here to distinguish good checked exceptions from bad:

  1. Out of client's control or Closed vs Open:

    Checked exceptions should only be used where the error case is out of control of both the API and the client programmer. This has to do with how open or closed the system is. In a constrained UI where the client programmer has control, say, over all of the buttons, keyboard commands etc that add and delete rows from the table view (a closed system), it is a client programming bug if it attempts to fetch data from a nonexistent row. In a file-based operating system where any number of users/applications can add and delete files (an open system), it is conceivable that the file the client is requesting has been deleted without their knowledge so they should be expected to deal with it.

  2. Ubiquity:

    Checked exceptions should not be used on an API call that is made frequently by the client. By frequently I mean from a lot of places in the client code - not frequently in time. So a client code doesn't tend to try to open the same file a lot, but my table view gets RowData all over the place from different methods. In particular, I'm going to be writing a lot of code like

    if (model.getRowData().getCell(0).isEmpty())
    

and it will be painful to have to wrap in try/catch every time.

  1. Informing the User:

    Checked exceptions should be used in cases where you can imagine a useful error message being presented to the end user. This is the "and what will you do when it happens?" question I raised above. It also relates to item 1. Since you can predict that something outside of your client-API system might cause the file to not be there, you can reasonably tell the user about it:

    "Error: could not find the file 'goodluckfindingthisfile'"
    

    Since your illegal row number was caused by an internal bug and through no fault of the user, there's really no useful information you can give them. If your app doesn't let runtime exceptions fall through to the console it will probably end up giving them some ugly message like:

    "Internal error occured: IllegalArgumentException in ...."
    

    In short, if you don't think your client programmer can explain your exception in a way that helps the user, then you should probably not be using a checked exception.

So those are my rules. Somewhat contrived, and there will doubtless be exceptions (please help me refine them if you will). But my main argument is that there are cases like FileNotFoundException where the checked exception is as important and useful a part of the API contract as the parameter types. So we should not dispense with it just because it is misused.

Sorry, didn't mean to make this so long and waffly. Let me finish with two suggestions:

A: API programmers: use checked exceptions sparingly to preserve their usefulness. When in doubt use an unchecked exception.

B: Client programmers: get in the habit of creating a wrapped exception (google it) early on in your development. JDK 1.4 and later provide a constructor in RuntimeException for this, but you can easily create your own too. Here's the constructor:

public RuntimeException(Throwable cause)

Then get in the habit of whenever you have to handle a checked exception and you're feeling lazy (or you think the API programmer was overzealous in using the checked exception in the first place), don't just swallow the exception, wrap it and rethrow it.

try {
  overzealousAPI(thisArgumentWontWork);
}
catch (OverzealousCheckedException exception) {
  throw new RuntimeException(exception);  
}

Put this in one of your IDE's little code templates and use it when you're feeling lazy. This way if you really need to handle the checked exception you'll be forced to come back and deal with it after seeing the problem at runtime. Because, believe me (and Anders Hejlsberg), you're never going to come back to that TODO in your

catch (Exception e) { /* TODO deal with this at some point (yeah right) */}
SørenHN
  • 566
  • 5
  • 20
Rhubarb
  • 34,705
  • 2
  • 49
  • 38
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/238813/discussion-on-answer-by-rhubarb-the-case-against-checked-exceptions). – Jean-François Fabre Nov 02 '21 at 19:53
219

The thing about checked exceptions is that they are not really exceptions by the usual understanding of the concept. Instead, they are API alternative return values.

The whole idea of exceptions is that an error thrown somewhere way down the call chain can bubble up and be handled by code somewhere further up, without the intervening code having to worry about it. Checked exceptions, on the other hand, require every level of code between the thrower and the catcher to declare they know about all forms of exception that can go through them. This is really little different in practice to if checked exceptions were simply special return values which the caller had to check for. eg.[pseudocode]:

public [int or IOException] writeToStream(OutputStream stream) {
    [void or IOException] a= stream.write(mybytes);
    if (a instanceof IOException)
        return a;
    return mybytes.length;
}

Since Java can't do alternative return values, or simple inline tuples as return values, checked exceptions are are a reasonable response.

The problem is that a lot of code, including great swathes of the standard library, misuse checked exceptions for real exceptional conditions that you might very well want to catch several levels up. Why is IOException not a RuntimeException? In every other language I can let an IO exception happen, and if I do nothing to handle it, my application will stop and I'll get a handy stack trace to look at. This is the best thing that can happen.

Maybe two methods up from the example you want to catch all IOExceptions from the whole writing-to-stream process, abort the process and jump into the error reporting code; in Java you can't do that without adding ‘throws IOException’ at every call level, even levels that themselves do no IO. Such methods should not need to know about the exception handling; having to add exceptions to their signatures:

  1. unnecessarily increases coupling;
  2. makes interface signatures very brittle to change;
  3. makes the code less readable;
  4. is so annoying that it the common programmer reaction is to defeat the system by doing something horrible like ‘throws Exception’, ‘catch (Exception e) {}’, or wrapping everything in a RuntimeException (which makes debugging harder).

And then there's plenty of just ridiculous library exceptions like:

try {
    httpconn.setRequestMethod("POST");
} catch (ProtocolException e) {
    throw new CanNeverHappenException("oh dear!");
}

When you have to clutter up your code with ludicrous crud like this, it is no wonder checked exceptions receive a bunch of hate, even though really this is just simple poor API design.

Another particular bad effect is on Inversion of Control, where component A supplies a callback to generic component B. Component A wants to be able to let an exception throw from its callback back to the place where it called component B, but it can't because that would change the callback interface which is fixed by B. A can only do it by wrapping the real exception in a RuntimeException, which is yet more exception-handling boilerplate to write.

Checked exceptions as implemented in Java and its standard library mean boilerplate, boilerplate, boilerplate. In an already verbose language this is not a win.

aioobe
  • 413,195
  • 112
  • 811
  • 826
bobince
  • 528,062
  • 107
  • 651
  • 834
  • 15
    In your code example, it would be best to chain the exceptions so that the original cause can be found when reading the logs: throw CanNeverHappenException(e); – Esko Luontola Mar 06 '09 at 11:25
  • 5
    I disagree. Exceptions, checked or not, are exceptional conditions. Example: a method that retrieves an object via HTTP. The return value is else the object or nothing, all the things that can go bad are exceptional. Treating them as return values as it is done in C only leads to confusion and poor design. – Mister Smith Aug 22 '11 at 11:33
  • 19
    @Mister: What I'm saying is that checked exceptions as implemented in Java behave, in practice, more like return values as in C than they do the traditional ‘exceptions’ we might recognise from C++ and other pre-Java languages. And that IMO this does indeed lead to confusion and poor design. – bobince Aug 22 '11 at 13:23
  • 10
    Agree that the standard libraries misuse of checked exceptions definitely added to the confusion and bad catching behavior. And, often it's just from poor documentation, e.g. a tear down method like disconnect() that throws IOException when "some other I/O error occurs". Well, I was disconnecting! Am I'm leaking a handle or other resource? Do I need to retry? Without knowing _why_ it happened, I can't derive the action I should take and so I have to guess whether I should just swallow it, retry, or bail. – charstar Dec 03 '11 at 09:26
  • 32
    +1 for "API alternative return values". Interesting way of looking at checked exceptions. – Zsolt Török Dec 20 '11 at 12:38
  • 4
    I like the "alternative return values" notion. Some exception types aren't likely going to be useful to anyone but the immediate caller, and even if the caller can't handle the exception, the caller should wrap it in such a way that its caller will know it was thrown from a nested routine). I think the big problem with checked exception ties in with a bigger problem of exceptions in general: way too many different things are all wrapped up in an exception's type. The fact that Java distinguishes "checked versus unchecked" exceptions based upon the exception type makes things worse, but... – supercat Mar 26 '12 at 19:01
  • ...is not the root problem. What might have been helpful would have been to have a reliable means for a "catch" statement to indicate that it only wants to catch exceptions for which the immediate called routine wants to "take credit", and a convenient means for routines to indicate when they want to take credit for exceptions thrown by nested routines (or even their own, for that matter). Checked exceptions could provide that, sort of, if there were a convenient way of indicating declaratively that exceptions should be wrapped, without having to write imperative code to do it. – supercat Mar 26 '12 at 19:08
  • In many ways, though, what's needed is a standard "aggregate exception" type, with distinct "catch" and "resolve" statements; a "catch" statement should run code if any of its conditions matches an aggregate exception, but an aggregate exception should continue up the call stack until all parts are "resolved". No such feature exists in Java or .net, but I would think such a feature should be a part of new frameworks that are developed. – supercat Mar 26 '12 at 19:12
  • @MisterSmith In programming, "exceptional conditions" do not mean conditions that we can ignore. It means conditions that we know, despite our best efforts, will eventually happen one day, but we don't have a good way of addressing them. Open Office cannot reasonably do anything about a disk being unplugged in the middle of saving a file. An API can't help it if your code has a bug and passes in an illegal `null`. It makes very little sense to impose strict requirements on handling situations our code cannot effectively handle; the "best way" will be *very* context dependent. – jpmc26 Sep 27 '17 at 23:20
  • 10
    I think conceptually the idea of exceptions as an alternative return value makes sense, but I'd take it even further. It's an alternative **return mechanism**. Exceptions can pass the same value through **multiple entries in the function call stack**, silently bypassing swaths of code in the process. This is not something the normal `return` mechanism can do, and it is the reason that exceptions allow us to achieve decoupling. Bottom line, exceptions are *flow control*, contrary to the platitude. They are a more limited, more manageable (because of greater guarantees about state) GOTO. – jpmc26 Sep 27 '17 at 23:29
  • 1
    Unlike error return values, exceptions don’t have to be checked after every function call. The `try-catch` block can group functions so that error handling is not interleaved with the algorithm. Thus it’s not correct to equate checked exceptions with return values. – Shelby Moore III May 21 '18 at 10:25
89

Rather than rehash all the (many) reasons against checked exceptions, I'll pick just one. I've lost count of the number of times I've written this block of code:

try {
  // do stuff
} catch (AnnoyingcheckedException e) {
  throw new RuntimeException(e);
}

99% of the time I can't do anything about it. Finally blocks do any necessary cleanup (or at least they should).

I've also lost count of the number of times I've seen this:

try {
  // do stuff
} catch (AnnoyingCheckedException e) {
  // do nothing
}

Why? Because someone had to deal with it and was lazy. Was it wrong? Sure. Does it happen? Absolutely. What if this were an unchecked exception instead? The app would've just died (which is preferable to swallowing an exception).

And then we have infuriating code that uses exceptions as a form of flow control, like java.text.Format does. Bzzzt. Wrong. A user putting "abc" into a number field on a form is not an exception.

Ok, i guess that was three reasons.

cletus
  • 616,129
  • 168
  • 910
  • 942
  • 4
    But if an exception is properly catched, you can inform the user, do other tasks (log?) and exit the application in a controlled way. I agree that some API parts could have been designed better. And for the lazy programmer reason, well, I think as a programmer you are 100% responsible of your code. – Mister Smith Aug 23 '11 at 06:22
  • 3
    note that the try-catch-rethrow allows you to specify a message - I usually use it to add information about the contents of state variables. A frequent example is for IOExceptions to add the absolutePathName() of the file in question. – Thorbjørn Ravn Andersen Oct 29 '12 at 22:34
  • I think you identified the biggest problem with checked exceptions; if `foo` calls `bar`, and `bar` might unexpectedly throw a `wazooException` `foo` isn't prepared to handle, there should be an easy way for `foo` to simply declare that it isn't prepared to handle a `wazooException` from `bar`. Passing it up via `throws` is the *wrong* approach, since the caller won't be able to distinguish between a `wazooException` thrown by `foo`, for reasons `foo` was anticipating, and a `wazooException` thrown by `bar` for reasons `foo` was not expecting. – supercat Jan 24 '13 at 23:34
  • I like your third reason(was it a reason against checked exceptions really? anyways I liked it). But to the lazy programmer reason, I'l definitely kick out such a programmer from my team. – Aqeel Ashiq Sep 24 '13 at 08:37
  • 20
    I think IDEs such as Eclipse have a lot to blame for the number of times you've seen the empty catch block. Really, they should rethrow by default. – artbristol Nov 08 '13 at 11:10
  • 19
    "99% of the time I can't do anything about it" -- wrong, you can show the user a message saying "Could not connect to the server" or "The IO device failed", instead of just letting the app crash due to a little network hiccup. Both of your examples are arts of work from bad programmers. You should be attacking the bad programmers and not checked exceptions themselves. It's like me attacking insulin for not helping with my diabetes when I use it as salad dressing. – AxiomaticNexus Jun 25 '14 at 21:56
  • 4
    @YasmaniLlanes You cannot always do these things. Sometimes you have an interface to adhere to. And this is especially true when you design good maintainable APIs because you can't just start throwing side-effects all over the place. Both that, and the complexity it will introduce, will bite you severely on a large scale. So yes, 99% of the time, there's nothing to be done about it. – MasterMastic Aug 25 '15 at 20:07
  • 1
    @MasterMastic Why would the simple act of implementing an interface prevent you from alerting the user when a network connection is lost or a file failed to load? – AxiomaticNexus Aug 25 '15 at 20:57
  • @YasmaniLlanes Well, forgive and correct me if I'm wrong please (I'm not very familiar with Java), but if the interface doesn't expect the exception, well, what am I to do as an implementer? & how will I alert the user? do I have to carry my error-logging interface with me to every object that could fail? & what then? how do I exit the procedure? or maybe I should just exit like others said? well those are *all* horrible practices, aren't they? modularity is dead, complexity is sad, and if I just quit the application what happens to all my acquired resources (that aren't managed by the OS)?. – MasterMastic Aug 25 '15 at 21:53
  • @MasterMastic You're correct that if an interface does not declare a method to throw a checked exception, its implementation cannot either. In the rare situation that a specific implementation of an interface runs into a checked exception, then it is the responsibility of that specific implementation to handle it, after all, the calling code to the interface is not expecting this exception, it doesn't make sense to slap them in the face with one. Ideally you would return an appropriate result, or you can always wrap the checked exception in a non-checked one and throw that instead. – AxiomaticNexus Aug 25 '15 at 23:44
  • 1
    @YasmaniLlanes I haven't found this to be rare at all. And I don't think the interface should predict all exceptions. If you interface a service that gets a arbitrary string, an implementer can do so by reading from static memory, or get it from a local file, or network, or remote database, and endless possibilities exist. I'm sure you don't think the interface should predict all possible (infinite) exceptions. So I don't think it would be unreasonable to slap on exceptions. It's far from ideal, definitely, but ugh, it's not news that exceptions are a *horrible* mechanism. – MasterMastic Aug 26 '15 at 00:32
  • And yes, I really do end up throwing a RuntimeException to get around checked exceptions (which I argue are bad here). You say "appropriate result" but in my experience it's usually impossible (at least to us who believe null is by no means appropriate). Thank you very much for your response. – MasterMastic Aug 26 '15 at 00:32
  • @MasterMastic It depends on what the interface is declaring. If the interface is declaring something like "loadStageFile()" then an IOException is a given; the interface should declare it. If the interface is declaring something like "calculatePiDigit()" any exception that may happen in there is the implementation's problem. If your implementation for whatever reason calculates Pi from a file, then it is your job to catch IOExceptions, in which case you would probably want to wrap it in a RuntimeException. – AxiomaticNexus Aug 26 '15 at 02:52
  • @MasterMastic Keep in mind that these cases with interfaces are not even a show stopper. Checked exceptions are not taking anything away from you feature-wise. You are always free to use RuntimeExceptions if you want, but the common wisdom that this IOException should always be handled is still there, Java just makes sure that you stick to that common wisdom. – AxiomaticNexus Aug 26 '15 at 02:57
  • 2
    @AxiomaticNexus "a message ... instead of just letting the app crash". That's always an option, but this happens typically some 10-20 stack frames higher, which all get polluted by the checked exception. And usually, writing just `catch Exception` somewhere close to top frame is much better as this way you can be sure you miss nothing. Obviously, you can and usually should differentiate according to the exact exception class, but that's nothing you'd need checked exceptions for. Actually, they make things worse as you're oftentimes forced to wrap them and then inspect the cause instead. – maaartinus Dec 02 '17 at 14:22
  • 1
    @maaartinus I would hardly call pollution adding two words: "throws XyzException" to the signature of any method up the stack that, you know... throws XyzException. The benefits (ensuring you handle exceptions properly) far outweigh the costs (adding two words to the method signature). – AxiomaticNexus Dec 04 '17 at 18:23
  • @cletus What do you think java.text.Format ought to do instead of throwing an Exception? – Mohan Dec 21 '17 at 04:20
  • @Mohan: the `Format` example is hilarious, as directly above the throwing method, there is the method [`parseObject(String source, ParsePosition pos)`](https://docs.oracle.com/javase/1.5.0/docs/api/java/text/Format.html#parseObject(java.lang.String,%20java.text.ParsePosition)) which does not throw but return `null` on wrong input and updates the position object accordingly. The programmer has the choice. – Holger Jan 25 '18 at 14:54
  • This is not an argument. Allowing a lazy default programmer action to become the lazy language default has nothing to recommend it. – user207421 Mar 21 '21 at 09:25
65

I know this is an old question but I've spent a while wrestling with checked exceptions and I've something to add. Please forgive me for the length of it!

My main beef with checked exceptions is that they ruin polymorphism. It's impossible to make them play nicely with polymorphic interfaces.

Take the good ol' Java List interface. We have common in-memory implementations like ArrayList and LinkedList. We also have the the skeletal class AbstractList which makes it easy to design new types of list. For a read-only list we need to implement only two methods: size() and get(int index).

This example WidgetList class reads some fixed-size objects of type Widget (not shown) from a file:

class WidgetList extends AbstractList<Widget> {
    private static final int SIZE_OF_WIDGET = 100;
    private final RandomAccessFile file;

    public WidgetList(RandomAccessFile file) {
        this.file = file;
    }

    @Override
    public int size() {
        return (int)(file.length() / SIZE_OF_WIDGET);
    }

    @Override
    public Widget get(int index) {
        file.seek((long)index * SIZE_OF_WIDGET);
        byte[] data = new byte[SIZE_OF_WIDGET];
        file.read(data);
        return new Widget(data);
    }
}

By exposing the Widgets using the familiar List interface, you can retrieve items (list.get(123)) or iterate a list (for (Widget w : list) ...) without needing to know about WidgetList itself. One can pass this list to any standard methods that use generic lists, or wrap it in a Collections.synchronizedList. Code that uses it need neither know nor care whether the "Widgets" are made up on the spot, come from an array, or are read from a file, or a database, or from across the network, or from a future subspace relay. It will still work correctly because the List interface is correctly implemented.

Except it isn't. The above class doesn't compile because the file access methods may throw an IOException, a checked exception which you have to "catch or specify". You can't specify it as thrown -- the compiler won't let you because that would violate the contract of the List interface. And there is no useful way that WidgetList itself can handle the exception (as I'll expound on later).

Apparently the only thing to do is catch and rethrow checked exceptions as some unchecked exception:

@Override
public int size() {
    try {
        return (int)(file.length() / SIZE_OF_WIDGET);
    } catch (IOException e) {
        throw new WidgetListException(e);
    }
}

public static class WidgetListException extends RuntimeException {
    public WidgetListException(Throwable cause) {
        super(cause);
    }
}

((Edit: Java 8 has added an UncheckedIOException class for exactly this case: for catching and rethrowing IOExceptions across polymorphic method boundaries. Kind of proves my point!))

So checked exceptions simply don't work in cases like this. You can't throw them. Ditto for a clever Map backed by a database, or an implementation of java.util.Random connected to a quantum entropy source via a COM port. As soon as you try to do anything novel with the implementation of a polymorphic interface, the concept of checked exceptions fails. But checked exceptions are so insidious that they still won't leave you in peace, because you still have to catch and rethrow any from lower-level methods, cluttering the code and cluttering the stack trace.

I find that the ubiquitous Runnable interface is often backed into this corner, if it calls something which throws checked exceptions. It can't throw the exception as is, so all it can do is clutter the code by catching and rethrowing as a RuntimeException.

Actually, you can throw undeclared checked exceptions if you resort to hacks. The JVM, at run time, doesn't care about checked exception rules, so we need to fool only the compiler. The easiest way to do this is to abuse generics. This is my method for it (class name shown because (before Java 8) it's required in the calling syntax for the generic method):

class Util {
    /**
     * Throws any {@link Throwable} without needing to declare it in the
     * method's {@code throws} clause.
     * 
     * <p>When calling, it is suggested to prepend this method by the
     * {@code throw} keyword. This tells the compiler about the control flow,
     * about reachable and unreachable code. (For example, you don't need to
     * specify a method return value when throwing an exception.) To support
     * this, this method has a return type of {@link RuntimeException},
     * although it never returns anything.
     * 
     * @param t the {@code Throwable} to throw
     * @return nothing; this method never returns normally
     * @throws Throwable that was provided to the method
     * @throws NullPointerException if {@code t} is {@code null}
     */
    public static RuntimeException sneakyThrow(Throwable t) {
        return Util.<RuntimeException>sneakyThrow1(t);
    }

    @SuppressWarnings("unchecked")
    private static <T extends Throwable> RuntimeException sneakyThrow1(
            Throwable t) throws T {
        throw (T)t;
    }
}

Hurray! Using this we can throw a checked exception any depth up the stack without declaring it, without wrapping it in a RuntimeException, and without cluttering the stack trace! Using the "WidgetList" example again:

@Override
public int size() {
    try {
        return (int)(file.length() / SIZE_OF_WIDGET);
    } catch (IOException e) {
        throw sneakyThrow(e);
    }
}

Unfortunately, the final insult of checked exceptions is that the compiler refuses to allow you to catch a checked exception if, in its flawed opinion, it could not have been thrown. (Unchecked exceptions do not have this rule.) To catch the sneakily thrown exception we have to do this:

try {
    ...
} catch (Throwable t) { // catch everything
    if (t instanceof IOException) {
        // handle it
        ...
    } else {
        // didn't want to catch this one; let it go
        throw t;
    }
}

That is a bit awkward, but on the plus side, it is still slightly simpler than the code for extracting a checked exception that was wrapped in a RuntimeException.

Happily, the throw t; statement is legal here, even though the type of t is checked, thanks to a rule added in Java 7 about rethrowing caught exceptions.


When checked exceptions meet polymorphism, the opposite case is also a problem: when a method is spec'd as potentially throwing a checked exception, but an overridden implementation doesn't. For example, the abstract class OutputStream's write methods all specify throws IOException. ByteArrayOutputStream is a subclass that writes to an in-memory array instead of a true I/O source. Its overridden write methods cannot cause IOExceptions, so they have no throws clause, and you can call them without worrying about the catch-or-specify requirement.

Except not always. Suppose that Widget has a method for saving it out to a stream:

public void writeTo(OutputStream out) throws IOException;

Declaring this method to accept a plain OutputStream is the right thing to do, so it can be used polymorphically with all kinds of outputs: files, databases, the network, and so on. And in-memory arrays. With an in-memory array, however, there is a spurious requirement to handle an exception that can't actually happen:

ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
    someWidget.writeTo(out);
} catch (IOException e) {
    // can't happen (although we shouldn't ignore it if it does)
    throw new RuntimeException(e);
}

As usual, checked exceptions get in the way. If your variables are declared as a base type that has more open-ended exception requirements, you have to add handlers for those exceptions even if you know they won't occur in your application.

But wait, checked exceptions are actually so annoying, that they won't even let you do the reverse! Imagine you currently catch any IOException thrown by write calls on an OutputStream, but you want to change the variable's declared type to a ByteArrayOutputStream, the compiler will berate you for trying to catch a checked exception that it says cannot be thrown.

That rule causes some absurd problems. For example, one of the three write methods of OutputStream is not overridden by ByteArrayOutputStream. Specifically, write(byte[] data) is a convenience method that writes the full array by calling write(byte[] data, int offset, int length) with an offset of 0 and the length of the array. ByteArrayOutputStream overrides the three-argument method but inherits the one-argument convenience method as-is. The inherited method does exactly the right thing, but it includes an unwanted throws clause. That was perhaps an oversight in the design of ByteArrayOutputStream, but they can never fix it because it would break source compatibility with any code that does catch the exception -- the exception that has never, is never, and never will be thrown!

That rule is annoying during editing and debugging too. E.g., sometimes I'll comment out a method call temporarily, and if it could have thrown a checked exception, the compiler will now complain about the existence of the local try and catch blocks. So I have to comment those out too, and now when editing the code within, the IDE will indent to the wrong level because the { and } are commented out. Gah! It's a small complaint but it seems like the only thing checked exceptions ever do is cause trouble.


I'm nearly done. My final frustration with checked exceptions is that at most call sites, there's nothing useful you can do with them. Ideally when something goes wrong we'd have a competent application-specific handler that can inform the user of the problem and/or end or retry the operation as appropriate. Only a handler high up the stack can do this because it's the only one that knows the overall goal.

Instead we get the following idiom, which is rampant as a way to shut the compiler up:

try {
    ...
} catch (SomeStupidExceptionOmgWhoCares e) {
    e.printStackTrace();
}

In a GUI or automated program the printed message won't be seen. Worse, it plows on with the rest of the code after the exception. Is the exception not actually an error? Then don't print it. Otherwise, something else is going to blow up in a moment, by which time the original exception object will be gone. This idiom is no better than BASIC's On Error Resume Next or PHP's error_reporting(0);.

Calling some kind of logger class is not much better:

try {
    ...
} catch (SomethingWeird e) {
    logger.log(e);
}

That is just as lazy as e.printStackTrace(); and still plows on with code in an indeterminate state. Plus, the choice of a particular logging system or other handler is application-specific, so this hurts code reuse.

But wait! There is an easy and universal way to find the application-specific handler. It's higher up the call stack (or it is set as the Thread's uncaught exception handler). So in most places, all you need to do is throw the exception higher up the stack. E.g., throw e;. Checked exceptions just get in the way.

I'm sure checked exceptions sounded like a good idea when the language was designed, but in practice I've found them to be all bother and no benefit.

Boann
  • 48,794
  • 16
  • 117
  • 146
  • For your size method with the WidgetList, I would cache the size in a variable and set it in the constructor. The constructor is free to throw an exception. This won't work if the file changes while using the WidgetList though, which would probably be bad if it did. – TofuBeer Nov 27 '13 at 03:20
  • 5
    SomeStupidExceptionOmgWhoCares well someone cared enough to throw it. So either it never should have been thrown (bad design) or you should really handle it. The same is true of the bad implementation of a pre-1.0 class (the byte array output stream) where the design was, unfortunately bad. – TofuBeer Nov 27 '13 at 03:22
  • 2
    The proper idiom would have been a directive that would catch any specified exceptions thrown by nested subroutine calls and rethrow them wrapped in a `RuntimeException`. Note that a routine could simultaneously be declared as `throws IOException` and yet also specify that any `IOException` thrown from a nested call should be considered unexpected and wrapped. – supercat Dec 26 '13 at 03:13
  • 21
    I'm a professional C# developer with some Java experience who stumbled on this post. I'm baffled as to why anyone would support this bizarre behavior. In .NET if I want to catch a specific type of exception, I can catch that. If I want to just let it get thrown up the stack, there's nothing to do. I wish Java wasn't so quirky. :) – aikeru Mar 15 '14 at 04:38
  • 1
    Concerning "sometimes I'll comment out a method call temporarily" - I learnt to use `if (false)` for this. It avoids the throw clause problem and the warning helps me to navigate back faster. +++ That said, I agree with everything you wrote. Checked exceptions have some value, but this value is negligible when compared to their cost. Nearly always they just get in the way. – maaartinus May 25 '17 at 04:03
  • A bit late to the party, but it gets even worse with lambdas (that appeared as a way to reduce boilerplate!). That said, regarding API calls with errors, you can wrap checked exceptions (where they occur) in a `RuntimeException` and have every API endpoint wrapped to a generic error handler that gets the **cause** of the exception and handle it, or return an appropriate error message to the user that accessed the API, possibly logging the error too. This is the most practical way I found to handle checked exceptions, but still annoying because I have to rethrow them. – Lucas Basquerotto Jun 30 '21 at 19:00
  • Your WidgetList example is perhaps one good argument against the belief that the correct handler is always somewhere up the call stack. You would probably have one place where you configure your list to use a particular file. That's a pretty good place to handle an exception, e.g. pick a fallback file (Consider adding a configurable exception handler to the list itself). But after you pass that list all over the place, I doubt you will remember to or could reasonably handle exceptions everywhere. So your application will crash instead of picking a fallback set of slightly ugglier widgets. – Boyan Hristov Oct 20 '21 at 22:01
48

Well, it's not about displaying a stacktrace or silently crashing. It's about being able to communicate errors between layers.

The problem with checked exceptions is they encourage people to swallow important details (namely, the exception class). If you choose not to swallow that detail, then you have to keep adding throws declarations across your whole app. This means 1) that a new exception type will affect lots of function signatures, and 2) you can miss a specific instance of the exception you actually -want- to catch (say you open a secondary file for a function that writes data to a file. The secondary file is optional, so you can ignore its errors, but because the signature throws IOException, it's easy to overlook this).

I'm actually dealing with this situation now in an application. We repackaged almost exceptions as AppSpecificException. This made signatures really clean and we didn't have to worry about exploding throws in signatures.

Of course, now we need to specialize the error handling at the higher levels, implementing retry logic and such. Everything is AppSpecificException, though, so we can't say "If an IOException is thrown, retry" or "If ClassNotFound is thrown, abort completely". We don't have a reliable way of getting to the real exception because things get repackaged again and again as they pass between our code and third-party code.

This is why I'm a big fan of the exception handling in python. You can catch only the things you want and/or can handle. Everything else bubbles up as if you rethrew it yourself (which you have done anyways).

I've found, time and time again, and throughout the project I mentioned, that exception handling falls into 3 categories:

  1. Catch and handle a specific exception. This is to implement retry logic, for example.
  2. Catch and rethrow other exceptions. All that happens here is usually logging, and its usually a trite message like "Unable to open $filename". These are errors you can't do anything about; only a higher levels knows enough to handle it.
  3. Catch everything and display an error message. This is usually at the very root of a dispatcher, and all it does it make sure it can communicate the error to the caller via a non-Exception mechanism (popup dialogue, marshaling an RPC Error object, etc).
Carl Manaster
  • 39,912
  • 17
  • 102
  • 155
Richard Levasseur
  • 14,562
  • 6
  • 50
  • 63
  • 6
    You could have made specific subclasses of AppSpecificException to allow separation while keeping the plain method signatures. – Thorbjørn Ravn Andersen Nov 01 '09 at 08:21
  • 1
    Also a very important addition to item 2, is that it allows you to ADD INFORMATION to the exception caught (e.g. by nesting in a RuntimeException). It is much, much better to have the name of the file not found in the stack trace, than hidden deep down in a log file. – Thorbjørn Ravn Andersen Nov 01 '09 at 08:25
  • 2
    Basically your argument is "Managing exceptions is tiring so I'd rather not deal with it". As the exception bubbles up it looses meaning and context making is practically useless. As designer of an API you should make is contractually clear as to what can be expected when things go wrong, if my program crashes because I was not informed that this or that exception can "bubbles up" then you, as designer, failed and as a result of your failure my system is not as stable as it can be. – Newtopian Nov 08 '09 at 04:07
  • 5
    Thats not what I'm saying at all. Your last sentence actually agrees with me. If everything is wrapped in AppSpecificException, then it doesn't bubble up (and meaning/context is lost), and, yes, the API client is not being informed - this is exactly what happens with checked exceptions (as they are in java), because people don't want to deal with functions with lots of `throws` declarations. – Richard Levasseur Nov 08 '09 at 06:33
  • 7
    @Newtopian -- exceptions can largely only be handled at the "business" or "request" level. It makes sense to fail or retry at large granularity, not for every tiny potential failure. For this reason, exception-handling best practice is summarized as "throw early, catch late". Checked exceptions make it *harder* to manage reliability at the correct level, and encourage vast numbers of mis-coded catch blocks. http://literatejava.com/exceptions/checked-exceptions-javas-biggest-mistake/ – Thomas W Jun 02 '14 at 02:09
  • You could add a method like `hasCause(Class extends Exception>... causeClasses)` (searching the whole chain) to your `AppSpecificException` and use it as easily as multiple catch clauses. – maaartinus May 25 '17 at 03:50
  • @maaartinus or just use a factory method for `AppSpecificException` that doesn’t create a new instance but returns a cause of the same type, if one exists. – Holger Jan 25 '18 at 15:02
  • Your python example is functionally equivalent to unchecked exceptions (If you don't wish to handle them they bubble up to where they can be handled well or at least displayed) and I completely agree--being forced to handle exceptions right at the call point is not preferable which is an excellent answer to the question. – Bill K Nov 21 '18 at 00:41
  • 1
    The counter point by James Gosling in literatejava.com link (via @thomas-w comment) is so convoluted. His argument is essentially that c-programmers do not check FILE_NOT_FOUND error code during fopen() so we force this behavior using checked exceptions to make programs robust. Even a FATFS lib for tiny microcontrollers lists 18 return codes. http://elm-chan.org/fsw/ff/doc/open.html. Good C programmers would check and print right error messages and Bad Java programmers would swallow the checked exception whole. What a load of cr*p! – rjha94 Jun 09 '22 at 10:06
26

SNR

Firstly, checked exceptions decrease the "signal-to-noise ratio" for the code. Anders Hejlsberg also talks about imperative vs declarative programming which is a similar concept. Anyway consider the following code snippets:

Update UI from non UI-thread in Java:

try {  
    // Run the update code on the Swing thread  
    SwingUtilities.invokeAndWait(() -> {  
        try {
            // Update UI value from the file system data  
            FileUtility f = new FileUtility();  
            uiComponent.setValue(f.readSomething());
        } catch (IOException e) {  
            throw new UncheckedIOException(e);
        }
    });
} catch (InterruptedException ex) {  
    throw new IllegalStateException("Interrupted updating UI", ex);  
} catch (InvocationTargetException ex) {
    throw new IllegalStateException("Invocation target exception updating UI", ex);
}

Update UI from non UI-thread in C#:

private void UpdateValue()  
{  
   // Ensure the update happens on the UI thread  
   if (InvokeRequired)  
   {  
       Invoke(new MethodInvoker(UpdateValue));  
   }  
   else  
   {  
       // Update UI value from the file system data  
       FileUtility f = new FileUtility();  
       uiComponent.Value = f.ReadSomething();  
   }  
}  

Which seems a lot clearer to me. When you start to do more and more UI work in Swing checked exceptions start to become really annoying and useless.

Jail Break

To implement even the most basic of implementations, such as Java's List interface, checked exceptions as a tool for design by contract fall down. Consider a list that is backed by a database or a filesystem or any other implementation that throws a checked exception. The only possible implementation is to catch the checked exception and rethrow it as an unchecked exception:

@Override
public void clear()  
{  
   try  
   {  
       backingImplementation.clear();  
   }  
   catch (CheckedBackingImplException ex)  
   {  
       throw new IllegalStateException("Error clearing underlying list.", ex);  
   }  
}  

And now you have to ask what is the point of all that code? The checked exceptions just add noise, the exception has been caught but not handled and design by contract (in terms of checked exceptions) has broken down.

Conclusion

  • Catching exceptions is different to handling them.
  • Checked exceptions add noise to the code.
  • Exception handling works well in C# without them.

I blogged about this previously.

aioobe
  • 413,195
  • 112
  • 811
  • 826
Luke Quinane
  • 16,447
  • 13
  • 69
  • 88
  • Update UI from non UI-thread in C#: - what if an exception occurs? – TofuBeer Apr 01 '09 at 03:46
  • 3
    In the example both Java and C# are just letting the exceptions propagate up without handling them (Java via IllegalStateException). The difference is that you may want to handle a FileNotFoundException but its unlikely that handling InvocationTargetException or InterruptedException will be useful. – Luke Quinane Apr 01 '09 at 04:25
  • 3
    And in the C# way how do I know that the I/O exception can occur? Also I would never throw an exception from run... I consider that abusing exception handling. Sorry but for that part of your code I just can see your side of it yet. – TofuBeer Apr 01 '09 at 15:36
  • 1
    The known exceptions are put into the C# "Javadoc"; good APIs will define all known exceptions this way. You may be able to catch a FileNotFound inside run() but some exceptions can't be handled there. Catching them inside run() but not properly handling isn't good. Perhaps I'm misunderstanding. – Luke Quinane Apr 01 '09 at 23:58
  • 8
    We are getting there :-) So with each new release of an API you have to comb through all your calls and look for any new exceptions that might happen? The can easily happen with internal to a company APIs since they don't have to worry about backwards compatibility. – TofuBeer Apr 02 '09 at 16:38
  • 4
    Did you mean *decrease* the signal-to-noise ratio? – neo2862 Nov 15 '09 at 09:53
  • You are mixing things here. C# is more recent than Java and has a simpler design for the every day tasks. You can achieve the same clean design in Java, adding your own libraries or utilities. – Mister Smith Aug 23 '11 at 06:36
  • 3
    @TofuBeer Isn't being forced to update your code after the interface of an underlaying API changed a good thing? If you had had only unchecked exceptions there, you'd have ended up with a broken/incomplete program without knowing it. – Francois Bourgeois Apr 04 '13 at 10:52
  • I think this answer hits the head on the nail. "Look how crufty the Java code becomes. Java is already verbose!" A few remarks though: Just rethrowing the IOExceptions and InterruptedExceptions and crash and burn like that is a bad idea. In 9 cases out of 10, there's a more responsible way of dealing with the situation than to sweep it under the carpet. Where to deal with it? You're doing UI stuff here, so here's the right place to do it! If you do this improvement in both snippets, the C# version starts to approach the Java version. ... – aioobe Jul 11 '17 at 04:39
  • ... So, in this case I'd actually claim that the checked exceptions in fact helped you write more responsible code. The `InvocationTargetException` is nothing but unfortunate. It should clearly have been a `RuntimeException`. It's from the early days of Java, and no one had experienced the annoyance checked exceptions had brought us today. I would however like to emphasize that this is an API design issue, rather than an issue with checked exceptions as a language feature. Is it hard to get right? Sure, sometimes. But not so hard that a good feature like this should be tossed out the window. – aioobe Jul 11 '17 at 04:44
23

Artima published an interview with one of the architects of .NET, Anders Hejlsberg, which acutely covers the arguments against checked exceptions. A short taster:

The throws clause, at least the way it's implemented in Java, doesn't necessarily force you to handle the exceptions, but if you don't handle them, it forces you to acknowledge precisely which exceptions might pass through. It requires you to either catch declared exceptions or put them in your own throws clause. To work around this requirement, people do ridiculous things. For example, they decorate every method with, "throws Exception." That just completely defeats the feature, and you just made the programmer write more gobbledy gunk. That doesn't help anybody.

Le Dude
  • 547
  • 5
  • 9
  • 2
    In fact, the chief architect. – Trap Mar 05 '09 at 12:11
  • 20
    I have read that, to me his argument boils down to "there are bad programmers out there". – TofuBeer Mar 05 '09 at 15:11
  • 7
    TofuBeer, not at all. The whole point is that many times you don't know what to do with the Exception that the called method throws, and the case you're really interested in isn't even mentioned. You open a file, you get an IO Exception, for instance... that's not my problem, so I throw it up. But the top-level calling method will just want to stop processing and inform the user that there's an unknown problem. The checked Exception didn't help at all. It was one of a million strange things that can happen. – Dan Rosenstark May 27 '09 at 12:19
  • 4
    @yar, if you don't like the checked exception, then do a "throw new RuntimeException("we did not expect this when doing Foo.bar()", e)" and be done with it. – Thorbjørn Ravn Andersen Nov 01 '09 at 09:32
  • 3
    TofuBeer, I think his real argument is that there are humans out there. And that on the whole, it's not convincing that the pain incurred using checked exceptions is less than the pain incurred without them. – Phil May 03 '10 at 00:23
  • 1
    @ThorbjørnRavnAndersen: That would be the right approach, but I would posit that such wrapping should occur implicitly if a method neither catches a checked exception nor indicates somehow that it should percolate up the stack as-is (even if `Foo`, which has a `throws WizzleException` clause calls `Bar` which has a matching clause, that should not suffice, since likely as not, `Bar`'s exception won't mean the same thing as `Foo`'s. Boilerplate code to do the thing that should be done in 90% of cases is just noise. – supercat Oct 29 '12 at 20:35
  • 2
    @supercat in my experience, checked exceptions mean that you think about error handling _much_ earlier in the development process. This result in higher quality code (given that errors may be recoverable). – Thorbjørn Ravn Andersen Oct 29 '12 at 22:05
  • 4
    @ThorbjørnRavnAndersen: A fundamental design weakness in Java, which .net unfortunately copied, is that it uses the type of an exception as both the primary means for deciding whether it should be acted upon, and the primary means of indicating the general type of thing that went wrong, when in fact the two issues are largely orthogonal. What matters is not what went wrong, but what state objects are in. Further, both .net and Java assume by default that acting upon and resolving an exception are generally the same thing, when in fact they're often different. – supercat Oct 29 '12 at 22:20
  • @supercat interesting. Is this elaborated somewhere? – Thorbjørn Ravn Andersen Oct 29 '12 at 22:28
  • 1
    @ThorbjørnRavnAndersen: Not that I know of; it's just my opinion. If one has a method like `LoadDocument()` and it throws any exception, the caller has to deal with the fact that the document didn't load. If the caller can survive without the document, the next thing the caller needs to know is whether the attempt to load the document had any dangerous side effects that weren't rolled back. And the exception type says *nothing* about that. If a failed attempt to load a document had no side-effects, informing the user that it couldn't load may be sufficient to handle the exception. – supercat Oct 29 '12 at 22:35
  • @ThorbjørnRavnAndersen: If the attempt to load the document corrupted a data structure which is shared with other open documents, informing the user of the problem may be appropriate, but the problem should *not* be considered resolved. Unfortunately, both Java and .net assume that a `catch` block will resolve just about any exception unless the code manually rethrows it. – supercat Oct 29 '12 at 22:37
  • @supercat in that case the `loadDocument()` method has too many responsibilities. The exception should be handled at a _much_ lower level instead of being allowed to interrupt the manipulation of shared data structures. What you describe is simply bad design and not the fault of the exception mechanism. – Thorbjørn Ravn Andersen Oct 30 '12 at 00:05
  • 1
    So he's arguing against bad programmers, not checked exceptions themselves. Not having checked exceptions only makes those bad programmers even worse. – AxiomaticNexus Jun 25 '14 at 21:45
22

I initially agreed with you, as I've always been in favour of checked exceptions, and began to think about why I don't like not having checked exceptions in .Net. But then I realised that I don't infact like checked exceptions.

To answer you question, yes, I like my programs to show stack traces, preferably really ugly ones. I want the application to explode into a horrible heap of the ugliest error messages you could ever want to see.

And the reason is because, if it does that, I have to fix it, and I have to fix it right away. I want to know immediately that there is a problem.

How many times do you actually handle exceptions? I'm not talking about catching exceptions -- I'm talking about handling them? It's too easy to write the following:

try {
  thirdPartyMethod();
} catch(TPException e) {
  // this should never happen
}

And I know you can say that it's bad practice, and that 'the answer' is to do something with the exception (let me guess, log it?), but in the Real World (tm), most programmers just don't do it.

So yes, I don't want to catch exceptions if I don't have to do so, and I want my program to blow up spectacularly when I screw up. Silently failing is the worst possible outcome.

tsimon
  • 8,362
  • 2
  • 30
  • 41
  • Java encourages you to do this sort of thing, so that you don't have to add every type of exception to every method signature. – yfeldblum Mar 05 '09 at 12:00
  • I handle the exception, with code inside of the catch 100% of the time. The code is more than simply logging the fact that the exception is not too often. Most often the code is throwing a different exception type. – TofuBeer Mar 05 '09 at 15:31
  • 19
    Funny.. ever since I embraced checked exceptions correctly and used them appropriately my programs stopped blowing up in huge steaming pile of in your face customer dissatisfaction. If while developing you have big ugly bad stack trace then the customer is bound to get them as well. D'love to see his face when he sees ArrayIndexOutOfBoundsException with a mile high stack trace on his crashed system instead of a little tray notification saying that the color config for button XYZ could not be parsed so the default was used instead with the software happily humming along – Newtopian Aug 07 '09 at 16:46
  • 1
    Perhaps what Java needs is a "cantHandle" declaration which would specify that a method or try/catch block of code isn't prepared to handle a particular exception that occurs within it, and that any such exception that occurs via means other than an explicit throw within that method (as opposed to a called method) should be automatically wrapped and rethrown in a RuntimeException. IMHO, checked exceptions should *rarely* propagate up the call stack without being wrapped. – supercat Jan 24 '13 at 23:52
  • 5
    @Newtopian -- I write server & high-reliability software & have been doing so for 25 years. My programs have _never_ blown up, and I work with high-availability, retry & reconnect, integration-based financial & military systems. I have an absolute objective basis to prefer runtime exceptions. Checked exceptions make it more difficult to follow correct "throw early, catch late" best practice. Correct reliability & error-handling are at the "business", "connection" or "request" level. (Or occasionally when parsing data). Checked exceptions get in the way of doing it right. – Thomas W Jun 02 '14 at 02:39
  • 1
    The exceptions you're talking about here are `RuntimeExceptions` which indeed you don't have to catch, and I agree you should let the program blow up from. The exceptions you should always catch and handle are the checked exceptions like `IOException`. If you get an `IOException`, there's nothing to fix in your code; your program should not blow up just because there was a network hiccup. – AxiomaticNexus Jun 25 '14 at 21:25
  • Is there a static analysis tool out there which can find empty exception handlers and warn programmers, or do some IDEs already do it? – MauganRa Aug 31 '16 at 10:10
22

The article Effective Java Exceptions explains nicely when to use unchecked and when to use checked exceptions. Here are some quotes from that article to highlight the main points:

Contingency: An expected condition demanding an alternative response from a method that can be expressed in terms of the method's intended purpose. The caller of the method expects these kinds of conditions and has a strategy for coping with them.

Fault: An unplanned condition that prevents a method from achieving its intended purpose that cannot be described without reference to the method's internal implementation.

(SO doesn't allow tables, so you might want to read the following from the original page...)

Contingency

  • Is considered to be: A part of the design
  • Is expected to happen: Regularly but rarely
  • Who cares about it: The upstream code that invokes the method
  • Examples: Alternative return modes
  • Best Mapping: A checked exception

Fault

  • Is considered to be: A nasty surprise
  • Is expected to happen: Never
  • Who cares about it: The people who need to fix the problem
  • Examples: Programming bugs, hardware malfunctions, configuration mistakes, missing files, unavailable servers
  • Best Mapping: An unchecked exception
Community
  • 1
  • 1
Esko Luontola
  • 73,184
  • 17
  • 117
  • 128
  • I know when to use them, I want to know why people who don't follow that advice... don't follow that advice :-) – TofuBeer Mar 05 '09 at 15:45
  • What are _programming bugs_ and how to distinguish them from _usage bugs_? Is it a programming bug if the user passes the wrong arguments to the program? From the Java point of view it might be no programming bug but from the shell script point of view it is a programming bug. So what are invalid arguments in `args[]`? Are they a Contingency or a Fault? – ceving Mar 12 '13 at 14:50
  • 4
    @TofuBeer -- Because the Java library designers, chose to put all kinds of unrecoverable low-level failures as _checked exceptions_ when they clearly should have been _unchecked_. FileNotFound is the only IOException which should be checked, for example. With regard to JDBC -- only connecting to the database, can reasonably be considered a _contingency_. All other SQLExceptions should have been _failures_ and unchecked. Error handling should correctly be at the "business" or "request" level -- see the "throw early, catch late" best practice. Checked exceptions are a barrier to that. – Thomas W Jun 02 '14 at 02:21
  • 1
    There is a single huge flaw in your argument. "Contingency" must NOT be handled through exceptions, but through business code and method return values. Exceptions are for, as the word says, EXCEPTIONAL situations, therefore Faults. – Matteo Mosca Dec 16 '14 at 16:15
  • @MatteoMosca Error return codes tend to get ignored and that's enough to disqualify them. Actually, anything unusual can oftentimes be only handled somewhere up in the stack and that's a use case for exceptions. I could imagine something like `File#openInputStream` returning `Either` - if that's what you mean, then we may agree. – maaartinus Dec 02 '17 at 15:12
  • @maaartinus That's exactly what I meant. – Matteo Mosca Dec 03 '17 at 15:27
20

I have been working with several developers in the last three years in relatively complex applications. We have a code base that uses Checked Exceptions quite often with proper error handling, and some other that doesn't.

So far, I have it found easier to work with the code base with Checked Exceptions. When I am using someone else's API, it is nice that I can see exactly what kind of error conditions I can expect when I call the code and handle them properly, either by logging, displaying or ignoring (Yes, there is valid cases for ignoring exceptions, such as a ClassLoader implementation). That gives the code I am writing an opportunity to recover. All runtime exceptions I propagate up until they are cached and handled with some generic error handling code. When I find a checked exception that I don't really want to handle at a specific level, or that I consider a programming logic error, then I wrap it into a RuntimeException and let it bubble up. Never, ever swallow an exception without a good reason (and good reasons for doing this are rather scarce)

When I work with the codebase that does not have checked exceptions, it makes it to me a little bit harder to know before hand what can I expect when calling the function, which can break some stuff terribly.

This is all of course a matter of preference and developer skill. Both ways of programming and error handling can be equally effective (or noneffective), so I wouldn't say that there is The One Way.

All in all, I find it easier to work with Checked Exceptions, specially in large projects with lot of developers.

Mario Ortegón
  • 18,670
  • 17
  • 71
  • 81
  • 7
    I do to. For me they are an essential part of a contract. Without having to get to detailed in the API documentation, I can quickly know the likeliest of error scenarios. – Wayne Hartman May 18 '09 at 03:47
  • 3
    Agree. I experienced the necessity of checked exceptions in .Net once when I tried to make network calls. Knowing that a network hiccup could happen at any moment, I had to read through the entire documentation of the API's to find out what exception is it that I needed to catch specifically for that scenario. If C# had checked exceptions, I would have known immediately. Other C# developers would probably just let the app crash from a simple network error. – AxiomaticNexus Jun 25 '14 at 21:35
20

In short:

Exceptions are an API design question. -- No more, no less.

The argument for checked exceptions:

To understand why checked exceptions might not be good thing, let's turn the question around and ask: When or why are checked exceptions attractive, i.e. why would you want the compiler to enforce declaration of exceptions?

The answer is obvious: Sometimes you need to catch an exception, and that is only possible if the code being called offers a specific exception class for the error that you are interested in.

Hence, the argument for checked exceptions is that the compiler forces programmers to declare which exceptions are thrown, and hopefully the programmer will then also document specific exception classes and the errors that cause them.

In reality though, ever too often a package com.acme only throws an AcmeException rather than specific subclasses. Callers then need to handle, declare, or re-signal AcmeExceptions, but still cannot be certain whether an AcmeFileNotFoundError happened or an AcmePermissionDeniedError.

So if you're only interested in an AcmeFileNotFoundError, the solution is to file a feature request with the ACME programmers and tell them to implement, declare, and document that subclass of AcmeException.

So why bother?

Hence, even with checked exceptions, the compiler cannot force programmers to throw useful exceptions. It is still just a question of the API's quality.

As a result, languages without checked exceptions usually do not fare much worse. Programmers might be tempted to throw unspecific instances of a general Error class rather than an AcmeException, but if they care at all about their API quality, they will learn to introduce an AcmeFileNotFoundError after all.

Overall, the specification and documentation of exceptions is not much different from the specification and documentation of, say, ordinary methods. Those, too, are an API design question, and if a programmer forgot to implement or export a useful feature, the API needs to be improved so that you can work with it usefully.

If you follow this line of reasoning, it should be obvious that the "hassle" of declaring, catching, and re-throwing of exceptions that is so common in languages like Java often adds little value.

It is also worth noting that the Java VM does not have checked exceptions -- only the Java compiler checks them, and class files with changed exception declarations are compatible at run time. Java VM security is not improved by checked exceptions, only coding style.

David Lichteblau
  • 3,531
  • 2
  • 22
  • 12
  • 4
    Your argument argues against itself. If "sometimes you need to catch an exception" and API quality is often poor, without checked exceptions you won't know whether the designer neglected to document that a certain method throws an exception that needs to be caught. Couple that with throwing `AcmeException` rather than `AcmeFileNotFoundError` and good luck figuring out what you did wrong and where you need to catch it. Checked exceptions provide programmers a modicum of protection against bad API design. – Eva Feb 28 '13 at 16:27
  • 1
    Java library design made serious mistakes. 'Checked exceptions' were for predictable & recoverable contingencies -- such as file not found, failure to connect. They were never meant or suited for low-level systemic failure. It would have been fine to force opening a file to be checked, but there is no sensible retry or recovery for failure to write a single byte/ execute a SQL query etc. Retry or recovery are correctly handled at the "business" or "request" level, which checked exceptions make pointlessly difficult. http://literatejava.com/exceptions/checked-exceptions-javas-biggest-mistake/ – Thomas W Jun 02 '14 at 02:14
19

Exception categories

When talking about exceptions I always refer back to Eric Lippert's Vexing exceptions blog article. He places exceptions into these categories:

  • Fatal - These exceptions are not your fault: you cannot prevent then, and you cannot sensibly handle them. For example, OutOfMemoryError or ThreadAbortException.
  • Boneheaded - These exceptions are your fault: you should have prevented them, and they represent bugs in your code. For example, ArrayIndexOutOfBoundsException, NullPointerException or any IllegalArgumentException.
  • Vexing - These exceptions are not exceptional, not your fault, you cannot prevent them, but you'll have to deal with them. They are often the result of an unfortunate design decision, such as throwing NumberFormatException from Integer.parseInt instead of providing an Integer.tryParseInt method that returns a boolean false on parse failure.
  • Exogenous - These exceptions are usually exceptional, not your fault, you cannot (reasonably) prevent them, but you must handle them. For example, FileNotFoundException.

An API user:

  • must not handle fatal or boneheaded exceptions.
  • should handle vexing exceptions, but they should not occur in an ideal API.
  • must handle exogenous exceptions.

Checked exceptions

The fact that the API user must handle a particular exception is part of the method's contract between the caller and the callee. The contract specifies, among other things: the number and types of arguments the callee expects, the type of return value the caller can expect, and the exceptions the caller is expected to handle.

Since vexing exceptions should not exist in an API, only these exogenous exceptions must be checked exceptions to be part of the method's contract. Relatively few exceptions are exogenous, so any API should have relatively few checked exceptions.

A checked exception is an exception that must be handled. Handling an exception can be as simple as swallowing it. There! The exception is handled. Period. If the developer wants to handle it that way, fine. But he can't ignore the exception, and has been warned.

API problems

But any API that has checked vexing and fatal exceptions (e.g. the JCL) will put unnecessary strain on the API users. Such exceptions have to be handled, but either the exception is so common that it should not have been an exception in the first place, or nothing can be done when handling it. And this causes Java developers to hate checked exceptions.

Also, many APIs don't have a proper exception class hierarchy, causing all kinds of non-exogenous exception causes to be represented by a single checked exception class (e.g. IOException). And this also causes Java developers to hate checked exceptions.

Conclusion

Exogenous exceptions are those that are not your fault, could not have been prevented, and which should be handled. These form a small subset of all the exceptions that can get thrown. APIs should only have checked exogenous exceptions, and all other exceptions unchecked. This will make better APIs, put less strain on the API user, and therefore reduce the need to catch all, swallow or rethrow unchecked exceptions.

So don't hate Java and its checked exceptions. Instead, hate the APIs that overuse checked exceptions.

Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157
  • And misuse them by not having a hierarchy. – TofuBeer May 12 '13 at 17:02
  • 1
    FileNotFound and establishing a JDBC/network connection are _contingencies_ and correct to be checked exceptions, as these are predictable and (possible) recoverable. Most other IOExceptions, SQLExceptions, RemoteException etc are unpredictable & unrecoverable _failures_, and should have been **runtime exceptions.** Due to mistaken Java library design, we have all been lumped with this mistake & are now mostly using Spring & Hibernate (who got their design right). – Thomas W Jun 02 '14 at 02:45
  • You usually should handle boneheaded exceptions, though you may not want to call it "handling". For example, in a web server, I log them and show 500 to the user. As the exception is unexpected, there's about all I can do before the bug fix. – maaartinus Dec 02 '17 at 15:19
8

Ok... Checked exceptions are not ideal and have some caveat but they do serve a purpose. When creating an API there are specific cases of failures that are contractual of this API. When in the context of a strongly statically typed language such as Java if one does not use checked exceptions then one must rely on ad-hoc documentation and convention to convey the possibility of error. Doing so removes all benefit that the compiler can bring in handling error and you are left completely to the good will of programmers.

So, one removes Checked exception, such as was done in C#, how then can one programmatically and structurally convey the possibility of error ? How to inform the client code that such and such errors can occur and must be dealt with ?

I hear all sorts of horrors when dealing with checked exceptions, they are misused this is certain but so are unchecked exceptions. I say wait a few years when APIs are stacked many layers deep and you will be begging for the return of some kind of structured mean to convey failures.

Take the case when the exception was thrown somewhere at the bottom of the API layers and just bubbled up because nobody knew it was even possible for this error to occur, this even though it was a type of error that was very plausible when the calling code threw it (FileNotFoundException for example as opposed to VogonsTrashingEarthExcept... in which case it would not matter if we handle it or not since there is nothing left to handle it with).

Many have argued that not being able to load the file was almost always the end of the world for the process and it must die a horrible and painful death. So yeah.. sure ... ok.. you build an API for something and it loads file at some point... I as the user of said API can only respond... "Who the hell are you to decide when my program should crash !" Sure Given the choice where exceptions are gobbled up and leave no trace or the EletroFlabbingChunkFluxManifoldChuggingException with a stack trace deeper than the Marianna trench I would take the latter without a cinch of hesitation, but does this mean that it is the desirable way to deal with exception ? Can we not be somewhere in the middle, where the exception would be recast and wrapped each time it traversed into a new level of abstraction so that it actually means something ?

Lastly, most of the argument I see is "I don't want to deal with exceptions, many people do not want to deal with exceptions. Checked exceptions force me to deal with them thus I hate checked exception" To eliminate such mechanism altogether and relegate it to the chasm of goto hell is just silly and lacks jugement and vision.

If we eliminate checked exception we could also eliminate the return type for functions and always return a "anytype" variable... That would make life so much simpler now would it not ?

Newtopian
  • 7,543
  • 4
  • 48
  • 71
  • 2
    Checked exceptions would be useful if there were a declarative means of saying none of the method calls within a block are expected to throw some (or any) checked exceptions, and any such exceptions should automatically be wrapped and rethrown. They could be even more useful if calls to methods which were declared as throwing checked exceptions traded off call speed/return for exception-handling speed (so that expected exceptions could be handled almost as fast as normal program flow). Neither situation presently applies, though. – supercat Mar 14 '14 at 00:20
8

This isn't an argument against the pure concept of checked exceptions, but the class hierarchy Java uses for them is a freak show. We always call the things simply "exceptions" – which is correct, because the language specification calls them that too – but how is an exception named and represented in the type system?

By the class Exception one imagines? Well no, because Exceptions are exceptions, and likewise exceptions are Exceptions, except for those exceptions that are not Exceptions, because other exceptions are actually Errors, which are the other kind of exception, a kind of extra-exceptional exception that should never happen except when it does, and which you should never catch except sometimes you have to. Except that's not all because you can also define other exceptions that are neither Exceptions nor Errors but merely Throwable exceptions.

Which of these are the "checked" exceptions? Throwables are checked exceptions, except if they're also Errors, which are unchecked exceptions, and then there's the Exceptions, which are also Throwables and are the main type of checked exception, except there's one exception to that too, which is that if they are also RuntimeExceptions, because that's the other kind of unchecked exception.

What are RuntimeExceptions for? Well just like the name implies, they're exceptions, like all Exceptions, and they happen at run-time, like all exceptions actually, except that RuntimeExceptions are exceptional compared to other run-time Exceptions because they aren't supposed to happen except when you make some silly error, although RuntimeExceptions are never Errors, so they're for things that are exceptionally erroneous but which aren't actually Errors. Except for RuntimeErrorException, which really is a RuntimeException for Errors. But aren't all exceptions supposed to represent erroneous circumstances anyway? Yes, all of them. Except for ThreadDeath, an exceptionally unexceptional exception, as the documentation explains that it's a "normal occurrence" and that that's why they made it a type of Error.

Anyway, since we're dividing all exceptions down the middle into Errors (which are for exceptional execution exceptions, so unchecked) and Exceptions (which are for less exceptional execution errors, so checked except when they're not), we now need two different kinds of each of several exceptions. So we need IllegalAccessError and IllegalAccessException, and InstantiationError and InstantiationException, and NoSuchFieldError and NoSuchFieldException, and NoSuchMethodError and NoSuchMethodException, and ZipError and ZipException.

Except that even when an exception is checked, there are always (fairly easy) ways to cheat the compiler and throw it without it being checked. If you do you that you may get an UndeclaredThrowableException, except in other cases, where it could throw up as an UnexpectedException, or an UnknownException (which is unrelated to UnknownError, which is only for "serious exceptions"), or an ExecutionException, or an InvocationTargetException, or an ExceptionInInitializerError.

Oh, and we mustn't forget Java 8's snazzy new UncheckedIOException, which is a RuntimeException exception designed to let you throw the exception checking concept out the window by wrapping checked IOException exceptions caused by I/O errors (which don't cause IOError exceptions, although that exists too) that are exceptionally difficult to handle and so you need them to not be checked.

Thanks Java!

Boann
  • 48,794
  • 16
  • 117
  • 146
  • 3
    As far as I can say, this answer only says "Java's exceptions are a mess" in a full of irony, arguably funny way. What it seems not to do is explain why programmers tend to avoid trying to understand how these things are supposed to work. Also, in real-life cases (at least the ones I had a chance to deal with), if the programmers don't deliberately try to make their lives harder, the exceptions are nowhere near as complicated as you've described. – CptBartender Jun 28 '16 at 07:26
6

One important thing nobody mentioned is how it interferes with interfaces and lambda expressions.

Let's say you define a MyAppException extends Exception. It is the top level exception inherited by all exceptions thrown by your application. In some places you don't want to react to the particular exceptions, you want the caller to resolve it, so you declare throws MyAppException.

All looks OK until you want to use someone else's interface. Obviously they don't declare intention to throw MyAppException, so compiler doesn't allow you to even call your methods that declare throws MyAppException in there. This is especially painful with java.util.function.

However, if your exception extends RuntimeException, there will be no problem with interfaces. You can mention the exception in JavaDoc if you wish. But other than that it just silently bubbless through anything. Of course that means it can terminate your application. But in lots of enterprise software you have exception handling layer and unchecked exceptions save lots of trouble.

Vlasec
  • 5,500
  • 3
  • 27
  • 30
  • But this is exactly the point of the checked exceptions. If the interface does not specify checked exceptions, then the user of this interface may be sure, that no exceptions will be thrown. This basically means, that the implementation of the operation is not allowed to fail. And if your implementation cannot guarantee it, then you should not implement it. Or you should consider carefully, what to do with a failure because interface does not allow you to report it explicitly to the caller. – Dmitrii Semikin Nov 25 '20 at 16:46
  • @DmitriiSemikin The point is, there is some interesting syntax sugar coming in Java 8, with `Predicate`s, `Function`s etc. that gets cumbersome to use if there are checked exceptions. One would prefer to handle the exception outside the lambda, but the way checked exceptions are made doesn't allow for that. If `Predicate` threw `Exception` in its `test` method, then it would work with any checked exception, but it would always need to be nested in a try/catch-all, even if the lambda throws no exception at all, which would be worse than what we have currently. – Vlasec May 08 '21 at 11:58
  • If the lambdas were an integral part of the language from the start rather than some kind of syntax sugar over anonymous classes, maybe they would have some special interfaces where the checked exceptions thrown inside them would be automatically added to their `throws` declaration, and the obligation to declare or catch the checked exception would be transitioned to the class that uses the lambda. But since it is not the case, libraries generally prefer unchecked exceptions even for situations where checked exceptions would otherwise be a better idea, to protect the syntax sugar. – Vlasec May 08 '21 at 12:27
  • 1
    I would say, I agree, that lambdas and checked exceptions do not play nicely together. But probably it is also for reason. I find that having Lambdas throwing exceptions (either checked or unchecked) is not a good idea in general. Because you never know, where this lambda will be used (and consequently, where you need to catch the exception... it can be even other thread). So in case of Lambdas I personally would just give up on using exceptions(if it were possible)and would use other ways of reporting errors. The fact, that checked exceptions do not work well with lambdas just highlights it. – Dmitrii Semikin May 10 '21 at 14:51
  • I agree that checked exceptions are not a good idea in functional interfaces, in general. However, if you want to go for a different approach to reporting errors, then perhaps you should try Scala instead. In Java 8, if you are a bit pragmatic, you just throw an unchecked exception and catch it where appropriate. Otherwise you'll probably end up with much more boilerplate than you'd end up in Scala with its great pattern matching. I know newer Java has some pattern matching as well, but if it's as comfortable to use as Java 8 Optional, then I'd rather stay away from that. – Vlasec May 24 '21 at 13:34
  • 1
    The problem is with API's accepting only lambda's that throw no checked exceptions. The Stream API is the biggest culprit. It is however perfectly possible to write the Stream API in such a way that checked exceptions are possible, albeit a bit cumbersome because of lack of language support. See here: https://github.com/hjohn/MediaSystem-v2/blob/master/mediasystem-util/src/test/java/hs/mediasystem/util/checked/FlowTest.java – john16384 Oct 30 '21 at 09:51
  • The example is nice. With a bit of factory method support, there could be methods that create `Flow` with `0..N` thrown exception types, where `N > 2` wouldn't hurt as much. While I don't know of any way to completely avoid throws clause once it is parametrized this way, you could just add an unchecked exception called e.g. NoException and use it when no checked exceptions are provided. – Vlasec Nov 14 '21 at 00:01
  • As for language support, I wouldn't expect that. Functional languages tend to add the error state to the response itself, e.g. if you were writing your own implementation of integer arithmetic in Scala, you would use `def / (a: Int, b: Int): Either[ArithmeticError, Int]` as the output of division, and return `Right(3)` as a result of `10 / 3`, and `Left(ArithmeticError(...))` when someone tries `5 / 0`. Checked exceptions would be superficial there. – Vlasec Nov 14 '21 at 00:20
6

Indeed, checked exceptions on the one hand increase robustness and correctness of your program (you're forced to make correct declarations of your interfaces -the exceptions a method throws are basically a special return type). On the other hand you face the problem that, since exceptions "bubble up", very often you need to change a whole lot of methods (all the callers, and the callers of the callers, and so on) when you change the exceptions one method throws.

Checked exceptions in Java do not solve the latter problem; C# and VB.NET throw out the baby with the bathwater.

A nice approach that takes the middle road is described in this OOPSLA 2005 paper (or the related technical report.)

In short, it allows you to say: method g(x) throws like f(x), which means that g throws all the exceptions f throws. Voila, checked exceptions without the cascading changes problem.

Although it is an academic paper, I'd encourage you to read (parts of) it, as it does a good job of explaining what the benefits and downsides of checked exceptions are.

Eponymous
  • 6,143
  • 4
  • 43
  • 43
Kurt Schelfthout
  • 8,880
  • 1
  • 30
  • 48
6

The problem

The worst problem I see with exception handling mechanism is that it introduces code duplication in a big scale! Let's be honest: In most of projects in 95% of the time all that developers really need to do with exception is to communicate it somehow to the user (and, in some cases, to the development team as well, e.g. by sending an e-mail with the stack trace). So usually the same line/block of code is used in every place the exception is handled.

Let's assume that we do simple logging in each catch block for some type of checked exception:

try{
   methodDeclaringCheckedException();
}catch(CheckedException e){
   logger.error(e);
}

If it's a common exception there may be even several hundreds of such try-catch blocks in a larger codebase. Now let's assume that we need to introduce popup dialog based exception handling instead of console logging or start to additionally send an e-mail to the development team.

Wait a moment... are we really going to edit all of that several hundreds of locations in the code?! You get my point :-).

The solution

What we did to adress that issue was introducing the concept of exception handlers (to which I'll further refer as EH's) to centralize exception handling. To every class that needs to hande exceptions an instance of exception handler is injected by our Dependency Injection framework. So the typical pattern of exception handling now looks like this:

try{
    methodDeclaringCheckedException();
}catch(CheckedException e){
    exceptionHandler.handleError(e);
}

Now to customize our exception handling we only need to change the code in a single place (EH code).

Of course for more complex cases we can implement several subclasses of EHs and leverage features that our DI framework provides us. By changing our DI framework configuration we can easily switch EH implementation globally or provide specific implementations of EH to classes with special exception handling needs (for example using Guice @Named annotation).

That way we can differentiate exception handling behaviour in development and release version of application (eg. development - logging the error and halting the application, prod - logging the error with more details and letting the application continue its execution) with no effort.

Last one thing

Last but not least, it may seem that the same kind of centralisation can be obtained by just passing our exceptions "up" until they arrive to some top level exception handling class. But that leads to cluttering of code and signatures of our methods and introduces maintenance problems mentioned by others in this thread.

Community
  • 1
  • 1
Piotr Sobczyk
  • 6,443
  • 7
  • 47
  • 70
  • 7
    Exceptions are invented to do something useful with them. Writing them into a log file or rendering a pretty window is not useful, because the original problem does not get solved by this. Doing something useful requires trying a different solution strategy. Examples: If I am not able to get my data from server A I try it on server B. Or if algorithm A produces a heap overflow I try algorithm B which is much slower but might succeed. – ceving Mar 12 '13 at 15:12
  • 4
    @ceving Yeah, it's all good and true in theory. But now let's get back to practice word. Please answer really honestly how often you do it in your real-word project? What part of `catch` blocks in this real project do something really "useful" with exceptins? 10% would be good. Usual problems that generate exceptions are like trying to read configuration from file that doesn't exist, OutOfMemoryErrors, NullPointerExceptions, database constraint integrity errors etc, etc. Are you really trying to gracefully recover from all of them? I don't believe you :). Often there is just no way to recover. – Piotr Sobczyk Mar 13 '13 at 18:51
  • 3
    @PiotrSobczyk: If a program takes some action as a result of a suer request, and the operation fails in some fashion which hasn't damaged anything in the system state, notifying the user that the operation couldn't be completed is a perfectly useful way of handling the situation. The biggest failing of exceptions in C# and .net is that there's no consistent way to ascertain whether anything in the system state might have gotten damaged. – supercat Mar 15 '13 at 19:58
  • 5
    Correct, @PiotrSobczyk. Most often, the only correct action to take in response to an exception is to rollback the transaction & return an error response. Ideas of "solving exception" imply knowledge & authority we don't (and shouldn't) have, and violate encapsulation. If our application is not a DB, we shouldn't try to _fix_ the DB. Failing cleanly & avoiding writing erroneous data, ceving, is _useful enough_. – Thomas W Jun 02 '14 at 02:50
  • @PiotrSobczyk Yesterday, I dealt with a "could not read object" exception (which will only come about because the underlying database has been updated before the software - which should never happen but is a possibility due to human error) by failing over to a historical version of the database guaranteed to point to an old version of the object. – Eponymous Oct 10 '14 at 13:23
6

This article is the best piece of text on exception handling in Java I have ever read.

It favours unchecked over checked exceptions but this choice is explained very thouroughly and based on strong arguments.

I don't want to cite too much of the article content here (it's best to read it as a whole) but it covers most of arguments of unchecked exceptions advocates from this thread. Especially this argument (which seems to be quite popular) is covered:

Take the case when the exception was thrown somewhere at the bottom of the API layers and just bubbled up because nobody knew it was even possible for this error to occur, this even though it was a type of error that was very plausible when the calling code threw it (FileNotFoundException for example as opposed to VogonsTrashingEarthExcept... in which case it would not matter if we handle it or not since there is nothing left to handle it with).

The author "responses":

It is absolutely incorrect to assume that all runtime exceptions should not be caught and allowed to propagate to the very "top" of the application. (...) For every exceptional condition that is required to be handled distinctly - by the system/business requirements - programmers must decide where to catch it and what to do once the condition is caught. This must be done strictly according to the actual needs of the application, not based on a compiler alert. All other errors must be allowed to freely propagate to the topmost handler where they would be logged and a graceful (perhaps, termination) action will be taken.

And the main thought or article is:

When it comes to error handling in software, the only safe and correct assumption that may ever be made is that a failure may occur in absolutely every subroutine or module that exists!

So if "nobody knew it was even possible for this error to occur" there is something wrong with that project. Such exception should be handled by at least the most generic exception handler (e.g. the one that handles all Exceptions not handled by more specific handlers) as author suggests.

So sad not many poeple seems to discover this great article :-(. I recommend wholeheartly everyone who hesitates which approach is better to take some time and read it.

Piotr Sobczyk
  • 6,443
  • 7
  • 47
  • 70
5

To attempt to address just the unanswered question:

If you throw RuntimeException subclasses instead of Exception subclasses then how do you know what you are supposed to catch?

The question contains specious reasoning IMHO. Just because the API tells you what it throws doesn't mean you deal with it in the same way in all cases. To put it another way, the exceptions you need to catch vary depending on the context in which you use the component throwing the exception.

For example:

If I'm writing a connection tester for a database, or something to check the validity of a user entered XPath, then I'd probably want to catch and report on all checked and unchecked exceptions that are thrown by the operation.

If, however, I am writing a processing engine, I will likely treat an XPathException (checked) in the same way as an NPE: I would let it run up to the top of the worker thread, skip the rest of that batch, log the issue (or send it to a support department for diagnosis) and leave feedback for the user to contact support.

Dave E
  • 123
  • 1
  • 8
  • 3
    Exactly. Easy and straightforward, the way exception-handling be. As Dave says, correct exception-handling is normally done at a _high level_. "Throw early, catch late" is the principle. Checked exceptions make that difficult. – Thomas W Jun 02 '14 at 03:05
5

As folks have already stated, checked exceptions don't exist in Java bytecode. They are simply a compiler mechanism, not unlike other syntax checks. I see checked exceptions a lot like I see the compiler complaining about a redundant conditional: if(true) { a; } b;. That's helpful but I might have done this on purpose, so let me ignore your warnings.

The fact of the matter is, you aren't going to be able to force every programmer to "do the right thing" if you enforce checked exceptions and everyone else is now collateral damage who just hates you for the rule you made.

Fix the bad programs out there! Don't try to fix the language to not allow them! For most folks, "doing something about an exception" is really just telling the user about it. I can tell the user about an unchecked exception just as well, so keep your checked exception classes out of my API.

Martin
  • 2,815
  • 1
  • 21
  • 30
  • Right, I just wanted to emphasize the difference between unreachable code (that generates an error) and conditionals with a predictable outcome. I’ll remove this comment later. – Holger Jan 29 '18 at 08:14
4

My writeup on c2.com is still mostly unchanged from its original form: CheckedExceptionsAreIncompatibleWithVisitorPattern

In summary:

Visitor Pattern and its relatives are a class of interfaces where the indirect caller and interface implementation both know about an exception but the interface and direct caller form a library that cannot know.

The fundamental assumption of CheckedExceptions is all declared exceptions can be thrown from any point that calls a method with that declaration. The VisitorPattern reveals this assumption to be faulty.

The final result of checked exceptions in cases like these is a lot of otherwise useless code that essentially removes the compiler's checked exception constraint at runtime.

As for the underlying problem:

My general idea is the top-level handler needs to interpret the exception and display an appropriate error message. I almost always see either IO exceptions, communication exceptions (for some reason APIs distinguish), or task-fatal errors (program bugs or severe problem on backing server), so this should not be too hard if we allow a stack trace for a severe server problem.

Joshua
  • 40,822
  • 8
  • 72
  • 132
  • 1
    You should have something like DAGNodeException in the interface, then catch the IOException and convert it to a DAGNodeException: public void call(DAGNode arg) throws DAGNodeException; – TofuBeer Nov 07 '09 at 20:46
  • 3
    @TofuBeer, that 's exactly my point. I find that constantly wrapping and unwrapping exceptions is worse than removing checked exceptions. – Joshua Nov 07 '09 at 22:48
  • 2
    Well we disagree completely then... but your article still does not answer the real underlying question of how you stop your application from displaying a stack trace to the user when a runtime exception is thrown. – TofuBeer Nov 08 '09 at 01:54
  • 2
    @TofuBeer -- When it fails, telling the user it failed is correct! What's your alternative, other than to "paper over" the failure with 'null' or incomplete/incorrect data? Pretending it succeeded is a lie, that just makes things worse. With 25 years experience in high-reliability systems, retry logic should only be used carefully & where appropriate. I would also expect a Visitor to likely fail again, no matter how many times you retry it. Unless you're flying a plane, swapping to a second version of the same algorithm is impractical & implausible (and may fail anyway). – Thomas W Jun 02 '14 at 03:01
4

Checked exceptions were, in their original form, an attempt to handle contingencies rather than failures. The laudable goal was to highlight specific predictable points (unable to connect, file not found, etc) & ensure developers handled these.

What was never included in the original concept, was to force a vast range of systemic & unrecoverable failures to be declared. These failures were never correct to be declared as checked exceptions.

Failures are generally possible in code, and EJB, web & Swing/AWT containers already cater for this by providing an outermost “failed request” exception-handler. The most basic correct strategy is to rollback the transaction & return an error.

One crucial point, is that runtime & checked exceptions are functionally equivalent. There is no handling or recovery which checked exceptions can do, that runtime exceptions can’t.

The biggest argument against “checked” exceptions is that most exceptions can’t be fixed. The simple fact is, we don’t own the code/ subsystem that broke. We can’t see the implementation, we’re not responsible for it, and can’t fix it.

If our application is not a DB.. we shouldn't try and fix the DB. That would violate the principle of encapsulation.

Particularly problematic have been the areas of JDBC (SQLException) and RMI for EJB (RemoteException). Rather than identifying fixable contingencies as per the original “checked exception” concept, these forced pervasive systemic reliability issues, not actually fixable, to be widely declared.

The other severe flaw in the Java design, was that exception-handling should correctly placed at the highest possible "business" or "request" level. The principle here is "throw early, catch late". Checked exceptions do little but get in the way of this.

We have an obvious issue in Java of requiring thousands of do-nothing try-catch blocks, with a significant proportion (40%+) being miscoded. Almost none of these implement any genuine handling or reliability, but impose major coding overhead.

Lastly, "checked exceptions" are pretty much incompatible with FP functional programming.

Their insistence on "handle immediately" is at odds with both "catch late" exception-handling best practice, and any FP structure which abstracts loops/ or flow of control.

Many people talk about "handling" checked exceptions, but are talking through their hats. Continuing after a failure with null, incomplete or incorrect data to pretend success is not handling anything. It's engineering/ reliability malpractice of the lowest form.

Failing cleanly, is the most basic correct strategy for handling an exception. Rolling back the transaction, logging the error & reporting a "failure" response to the user are sound practice -- and most importantly, prevent incorrect business data being committed to the database.

Other strategies for exception-handling are "retry", "reconnect" or "skip", at the business, subsystem, or request level. All of these are general reliability strategies, and work well/ better with runtime exceptions.

Lastly, it is far preferable to fail, than to run with incorrect data. Continuing will either cause secondary errors, distant from the original cause & harder to debug; or will eventually result in erroneous data being committed. People get fired for that.

See:
- http://literatejava.com/exceptions/checked-exceptions-javas-biggest-mistake/

Thomas W
  • 13,940
  • 4
  • 58
  • 76
  • That was a nice answer, but it doesn't address the core of my question: How do you know to catch an exception and roll back? Or are you simply saying people should catch RuntimeException at the top level of everything to ensure code doesn't crash? – TofuBeer Jun 29 '14 at 16:49
  • 1
    @TofuBeer Your request (web) or event/action (GUI) handler essentially processes business operations, and always has a possibility of internal/infrastructure failure. Failures should be handled at the business level by rolling back -- as you say, with a comprehensible error message. Such 'reliability handler' catch clauses should generally catch 'Exception' to catch any runtime/or checked exceptions. Modality/type of failure is largely irrelevant to handling, except in the rare cases where a specific known contingency occurs & logic exists to recover from it. – Thomas W Jun 30 '14 at 02:24
  • You should not catch Exception that leads to particularly horrendous code that can hide legitimate failures (such as ArrayIndexOutOfBounds) where the code things it is something else. In essense you can easily hide bugs by doing what you are suggesting. – TofuBeer Jun 30 '14 at 08:11
  • 2
    My point is to _fail properly_ as the general strategy. Unchecked exceptions help that as they do not force catch blocks to be interposed. Catching & error-logging can then be left to a few outermost handlers, rather than miscoded thousands of times throughout the codebase _(which is actually what hides bugs)_. For arbitrary failures, unchecked exceptions are absolutely most correct. _Contingencies_ -- predictable outcomes such as insufficient funds -- are the only exceptions legitimately are worth making checked. – Thomas W Jun 11 '15 at 23:56
  • Thomas W, that still doesn't address the issue of how the outer layer knows what to catch though, which is the fundamental issue.That still doesn't address the issue of how the outer layer knows what to catch though, which is the fundamental issue. – TofuBeer Jun 14 '15 at 01:26
  • 2
    **My answer already above addresses this.** First and foremost, _1) Outermost failure handler should catch everything._ Beyond that, for specific identified sites only, _2) Specific expected contingencies can be caught and handled -- at the immediate site they are thrown._ That means file not found, insufficient funds etc at the point these could be recovered from -- no higher. Principle of encapsulation means that outer layers cannot/ should not be responsible to understand/ recover from failures deep inside. Third, _3) Everything else should be thrown outwards -- unchecked if possible._ – Thomas W Jun 15 '15 at 01:27
  • 2
    **Outermost handler catches Exception,** logs it, and returns a "failed" response or shows an error dialog. Very simple, not hard to define at all. The point is that every exception not immediately & locally recoverable, is an _unrecoverable failure_ due to principle of encapsulation. If the code that's meant to know about can't recover it, then the request overall fails cleanly & properly. This is the right way to do it properly. – Thomas W Jun 15 '15 at 01:34
  • very simple and very dangerous - you wind up catching things that are genuine bugs that way. Exception catches RuntimeException and RuntimeException indicates a programmer error. – TofuBeer Jun 17 '15 at 06:00
  • 2
    **Incorrect.** Outermost handler's job is to _fail cleanly & log errors_ on the 'request' boundary. Broken request fails properly, exception is reported, thread is able to continue to service next request. Such an outermost handler is a standard feature in Tomcat, AWT, Spring, EJB containers & the Java 'main' thread. – Thomas W Jun 17 '15 at 23:23
  • How am I wrong? Exception catches RuntimeException. The purpose of RuntimeException is to indicate programmer errors. – TofuBeer Jun 19 '15 at 04:09
  • 2
    Why is it dangerous to report "genuine bugs" at the request boundary or outermost handler??? I frequently work in systems integration & reliability, where correct reliability engineering is actually important, and use "unchecked exception" approaches to do so. I'm not really sure what you're actually debating -- seems like you might want to actually spend 3 months in the unchecked exception way, get a feel for it, and then perhaps we can discuss further. Thanks. – Thomas W Jun 25 '15 at 04:23
  • An ArrayIndexOutOfBounds exception is an example of something that should not be caught. In terms of System integration and dealing with unknown 3rd party code then, yes, you do have to deal with unforeseen thing, but this question is about throwing them not catching them. – TofuBeer Jun 25 '15 at 18:01
  • 2
    @TofuBeer I for sure want to catch all exceptions including AIOOBE *somewhere*. It's a programming error and must be reported to be fixed, but there absolutely no reason to ignore it completely. There's no danger in catching `RuntimeException`; on the opposite: It must be done somewhere in order to present 500 to the user and an error report to the developers. So there's an outer block like `try {...} catch (RuntimeException e) {...} catch (Exception e) {...} ` in my code (and surely also in Spring and other frameworks). – maaartinus Dec 02 '17 at 15:48
4

Anders speaks about the pitfalls of checked exceptions and why he left them out of C# in episode 97 of Software Engineering radio.

Chuck Conway
  • 16,287
  • 11
  • 58
  • 101
3

The programmer needs to know all of the exceptions that a method may throw, in order to use it correctly. So, beating him over the head with just some of the exceptions does not necessarily help a careless programmer avoid errors.

The slim benefit is outweighed by the burdensome cost (especially in larger, less flexible code bases where constantly modifying the interface signatures is not practical).

Static analysis can be nice, but truly reliable static analysis often inflexibly demands strict work from the programmer. There is a cost-benefit calculation, and the bar needs to be set high for a check that leads to a compile time error. It would be more helpful if the IDE took on the role of communicating which exceptions a method may throw (including which are unavoidable). Although perhaps it would not be as reliable without forced exception declarations, most exceptions would still be declared in documentation, and the reliability of an IDE warning is not so crucial.

Aleksandr Dubinsky
  • 22,436
  • 15
  • 82
  • 99
3

I think that this is an excellent question and not at all argumentative. I think that 3rd party libraries should (in general) throw unchecked exceptions. This means that you can isolate your dependencies on the library (i.e. you don't have to either re-throw their exceptions or throw Exception - usually bad practice). Spring's DAO layer is an excellent example of this.

On the other hand, exceptions from the core Java API should in general be checked if they could ever be handled. Take FileNotFoundException or (my favourite) InterruptedException. These conditions should almost always be handled specifically (i.e. your reaction to an InterruptedException is not the same as your reaction to an IllegalArgumentException). The fact that your exceptions are checked forces developers to think about whether a condition is handle-able or not. (That said, I've rarely seen InterruptedException handled properly!)

One more thing - a RuntimeException is not always "where a developer got something wrong". An illegal argument exception is thrown when you try and create an enum using valueOf and there's no enum of that name. This is not necessarily a mistake by the developer!

oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
  • 2
    Yes, it is a mistake by the developer. They clearly didn't use the right name, so they have to go back and fix their code. – AxiomaticNexus Jun 25 '14 at 21:41
  • @AxiomaticNexus No sane developer uses `enum` member names, simply because they use `enum` objects instead. So a wrong name only can come from the outside, be it an import file or whatever. One possible way to dealing with such names is calling `MyEnum#valueOf` and catching the IAE. Another way is to use a pre-filled `Map`, but these are implementation details. – maaartinus Dec 02 '17 at 15:54
  • @maaartinus There are cases where enum member names are used without the string coming from outside. For example, when you want to loop through all the members dynamically to do something with each. Furthermore, whether the string comes from outside or not is irrelevant. The developer has all the information they need, to know whether passing x string to "MyEnum#valueOf" will result in an error before passing it. Passing x string to "MyEnum#valueOf" anyway when it would have caused error, would clearly be a mistake on the developer's part. – AxiomaticNexus Dec 04 '17 at 18:52
3

A problem with checked exceptions is that exceptions are often attached to methods of an interface if even one implementation of that interface uses it.

Another problem with checked exceptions is that they tend to be misused. The perfect example of this is in java.sql.Connection's close() method. It can throw a SQLException, even though you've already explicitly stated that you're done with the Connection. What information could close() possibly convey that you'd care about?

Usually, when I close() a connection*, it looks something like this:

try {
    conn.close();
} catch (SQLException ex) {
    // Do nothing
}

Also, don't get me started on the various parse methods and NumberFormatException... .NET's TryParse, which doesn't throw exceptions, is so much easier to use it's painful to have to go back to Java (we use both Java and C# where I work).

*As an additional comment, a PooledConnection's Connection.close() doesn't even close a connection, but you still have to catch the SQLException due to it being a checked exception.

Powerlord
  • 87,612
  • 17
  • 125
  • 175
  • 2
    Right, any of the drivers can... the question is rather "why should the programmer care?" as he's done accessing the database anyway. The docs even warn you that you should always commit() or rollback() the current transaction before calling close(). – Powerlord Mar 05 '09 at 17:52
  • Many people think that close on a file cannot throw an exception... http://stackoverflow.com/questions/588546/does-close-ever-throw-an-ioexception are you 100% certain that there are no cases that it would matter? – TofuBeer Mar 05 '09 at 21:50
  • I'm 100% certain that there are no cases that it *would* matter and that the caller *wouldn't* put in a try/catch. – Martin May 17 '09 at 20:06
  • 1
    Excellent example with closing connections, Martin! I can only rephrase you: If we just explicitly stated that we're done with a connection why should be bother what's going on when we're closig it. There more cases like this that programmer doesn't really care if exception occurs and he is absolutely right about it. – Piotr Sobczyk Oct 29 '11 at 09:33
  • 1
    @PiotrSobczyk: Some SQL drivers will squawk if one closes a connection after starting a transaction but neither confirming it nor rolling it back. IMHO, squawking is better than silently ignoring the problem, at least in cases where squawking won't cause other exceptions to get lost. – supercat Mar 14 '14 at 00:21
2

The good proves that Checked Exception are not needed are:

  1. A lot of framework that does some work for Java. Like Spring that wraps JDBC exception to unchecked exceptions, throwing messages to the log
  2. Lot of languages that came after java, even on top on java platform - they do not use them
  3. Checked exceptions, it is kind prediction about how the client would use the code that throws an exception. But a developer who writes this code would never know about the system and business that client of code is working in. As an example Interfcace methods that force to throw checked exception. There are 100 implementation over the system, 50 or even 90 of implementations do not throw this exception, but the client still must to catch this exception if he user reference to that interface. Those 50 or 90 implementations tend to handle those exceptions inside themself, putting exception to the log (and this is good behavior for them). What we should do with that? I would better have some background logic that would do all that job - sending message to the log. And If I, as a client of code, would feel I need handle the exception - I will do it. I may forget about it, right - but if I use TDD, all my steps are covered and I know what I want.
  4. Another example when I'm working with I/O in java, it forces me to check all exception, if file does not exists? what I should do with that? If it does not exists, the system would not go to the next step. The client of this method, would not get expected content from that file - he can handle Runtime Exception, otherwise I should first check Checked Exception, put a message to log, then throw exception up out form the method. No...no - I would better do it automatically with RuntimeEception, that does it / lits up automatically. There is no any sense to handle it manually - I would be happy I saw an error message in the log (AOP can help with that.. something that fixes java). If, eventually, I deice that system should shows pop-up message to the end user - I will show it, not a problem.

I was happy if java would provide me with a choice what to use, when working with core libs, like I/O. Like provides two copies of same classes - one wrapped with RuntimeEception. Then we can compare what people would use. For now, though, many people would better go for some framework on top on java, or different language. Like Scala, JRuby whatever. Many just believe that SUN was right.

Michael-O
  • 18,123
  • 6
  • 55
  • 121
ses
  • 13,174
  • 31
  • 123
  • 226
  • 1
    Rather than having two versions of classes, there should be a concise way of specifying none of the method calls made by a block of code are not expected to throw exceptions of certain types, and that any such exceptions should be wrapped via some specified means and rethrown (by default, create a new `RuntimeException` with an appropriate inner exception). It is unfortunate that it's more concise to have the outer method `throws` an exception from the inner method, than to have it wrap exceptions from the inner method, when the latter course of action would more often be correct. – supercat May 13 '13 at 19:03
2

Robert C. Martin also does not recommend using checked exception in his book Clean Code and considers that checked exception is an Open-Closed Principle violation:

What price? The price of checked exceptions is an Open/Closed Principle1 violation. If you throw a checked exception from a method in your code and the catch is three levels above, you must declare that exception in the signature of each method between you and the catch. This means that a change at a low level of the software can force signature changes on many higher levels. The changed modules must be rebuilt and redeployed, even though nothing they care about changed.

MWiesner
  • 8,868
  • 11
  • 36
  • 70
Zrom
  • 1,192
  • 11
  • 24
1

We've seen some references to C#'s chief architect.

Here's an alternate point of view from a Java guy about when to use checked exceptions. He acknowledges many of the negatives others have mentioned: Effective Exceptions

  • 2
    The problem with checked exceptions in Java stems from a deeper problem, which is that way too much information is encapsulated in the TYPE of the exception, rather than in properties of an instance. It would be useful to have checked exceptions, if being "checked" was an attribute of throw/catch sites, and if one could declaratively specify whether a checked exception which escapes a block of code should be remain as a checked exception, or be seen by any enclosing block as an unchecked exception; likewise catch blocks should be able to specify that they only want checked exceptions. – supercat Aug 02 '12 at 18:33
  • 1
    Suppose a dictionary-lookup routine is specified to throw some particular type of exception if an attempt is made to access a non-existent key. It may be reasonable for client code to catch such an exception. If, however, some method used by the lookup routine happens to throw that same type of exception in a manner the lookup routine doesn't expect, the client code probably shouldn't catch it. Having checked-ness be a property of exception *instances*, throw sites, and catch sites, would avoid such issues. The client would catch 'checked' exceptions of that type, dodging unexpected ones. – supercat Aug 02 '12 at 18:38
1

Despite having read the whole page, I still can't find a single reasonable argument against checked exceptions. Most people are instead talking about poor API design, either at some Java classes or at their own classes.

The only scenario where this feature may be annoying is prototiping. This could be solved by adding some mechanism to the language (for instance, some @supresscheckedexceptions annotation). But for regular programming, I think checked exceptions are a good thing.

Mister Smith
  • 27,417
  • 21
  • 110
  • 193
  • 2
    Best-practice "throw early, catch late" is incompatible with checked exception's insistence that they be handled _immediately_. It also prevents FP functional programming approaches. See: http://literatejava.com/exceptions/checked-exceptions-javas-biggest-mistake/ – Thomas W Jun 02 '14 at 03:02
  • There's no insistence on being handled immediately, only on being handled. You can declare that your method throws some exceptions and catch them as late as you want. And you can throw as early as you want as well. – Mister Smith Jun 02 '14 at 15:15
  • 3
    Exponential expansion through the call tree is effectively an insistence on being handled immediately. This could have been could worthwhile if applied solely to _contingencies_, which are predictable & potentially recoverable, but 'checked' behavior was erroneously widened to a broad range of unpredictable & unrecoverable _failures_. 'File open' or 'connect JDBC' are reasonable to require checked -- most other IOException, SQLException, RemoteException not so. This was a major error in Java library design. See my answer & a basic primer on exception-handling. – Thomas W Jun 02 '14 at 21:59
  • @ThomasW I've read your link and your answer, and I still I disagree. Checked exceptions are not bad in general, although I agree in that some particular exceptions in the API should have been made unchecked. – Mister Smith Jun 03 '14 at 15:31
  • @ThomasW And the principle of "throw early, catch late" is highly debatable. The throw early part is ok, but you can't default to catching late always. It depends. For instance, if I'm coding a class that interfaces with a WS, I might run into, lest say, `IOException`, `ParsingException`, `RemoteException`, `PermissionException` and so on. Here we can catch early to handle them in this layer and either return null/false/-1/whatever or envelope them in a custom WSException (of course checked, otherwise client classes might forget to handle them). – Mister Smith Jun 03 '14 at 15:32
  • 1
    "Catch late" is based on the level at which failure can be isolated -- most times, those are the business/ request or outbound connection/ request level. Simple & correct. – Thomas W Jun 04 '14 at 02:23
  • 1
    Returning null/false/-1 is **incorrect practice** as it mis-represents success to your client! This is a strict no-no, as it enables execution to continue with incomplete/invalid/incorrect data to either fail later (bad) or commit to the DB (worse). If parts of the business logic are **genuinely optional**, which you haven't stated, then a try/catch allow those to continue with a warning. Non-valid values and spreading bad data around the application are neither good nor necessary. – Thomas W Jun 04 '14 at 02:32
  • 3
    Best-practice exception handling is based on _actually_ how exceptions/errors can best be correctly handled (logging, reporting, sometimes recovered). This a science, not an art.. Getting it 100% optimal & correct is actually simple & easy -- so long as we are not pushed (by mistaken library design) to "handle early". As we can see, that mainly just encourages mistaken practice. – Thomas W Jun 04 '14 at 02:36
  • @MisterSmith You can't ever forget to handle a `WSException` or any other if you `catch (Exception e)` on some close-to-top level. You may or may not want some special handling, but the basic principle is to handle everything. For special handling you can use `try {...} catch (WSException) {...} catch (Exception e) {...}`, but it's only needed if you can do something special about it (you may want to retry it, but that holds for `TransactionLockTimeExceeded`, too). – maaartinus Dec 02 '17 at 16:05
0

Here's one argument against checked exceptions (from joelonsoftware.com):

The reasoning is that I consider exceptions to be no better than "goto's", considered harmful since the 1960s, in that they create an abrupt jump from one point of code to another. In fact they are significantly worse than goto's:

  • They are invisible in the source code. Looking at a block of code, including functions which may or may not throw exceptions, there is no way to see which exceptions might be thrown and from where. This means that even careful code inspection doesn't reveal potential bugs.
  • They create too many possible exit points for a function. To write correct code, you really have to think about every possible code path through your function. Every time you call a function that can raise an exception and don't catch it on the spot, you create opportunities for surprise bugs caused by functions that terminated abruptly, leaving data in an inconsistent state, or other code paths that you didn't think about.
finnw
  • 47,861
  • 24
  • 143
  • 221
  • 3
    +1 You might want to summarize the argument in your answer though? They are like invisible gotos and early exits for your routines, scattered throughout the program. – MarkJ Mar 05 '09 at 09:20
  • 18
    That's more an argument against Exceptions in general. – Ionuț G. Stan Mar 05 '09 at 09:36
  • 14
    have you actually read the article !! Firstly he talks about exceptions in general, secondly the section "They are invisible in the source code" applies specifically to UNCHECKED exception. This is the whole point of checked exception... so that you KNOW what code throws what where – Newtopian Aug 07 '09 at 16:55
  • Part of the argument against checked exceptions is that actually you _don't_ know what is thrown where. Yes, you know that a method _might_ throw its declared checked exceptions (although there are many annoying cases where an exception is declared even though you know that particular implementation can never throw that exception)... and, it could throw _any_ unchecked exception. Focusing on the former tends to make developers neglect the latter. – DNA Aug 01 '12 at 08:33
  • 1
    Would people quit with the "this feature is a goto in disguise"! If statements are a form of goto, loops are a form of goto. The problem with gotos is that they're too powerful and not specific enough. You can use goto everywhere, which makes it difficult to know when to stop. When you have a "goto" construct like exceptions, break statements, continue, etc., you can tell exactly what it's being used for. – Eva Mar 06 '13 at 18:24
  • 2
    @Eva They are not the same. With a goto statement you can see the `goto` keyword. With a loop you can see the closing brace or the `break` or `continue` keyword. All of them jump to a point in the current method. But you cannot always see the `throw`, because often it is not in the current method but in another method that it calls (possibly indirectly.) – finnw Mar 07 '13 at 00:45
  • 5
    @finnw Functions are themselves a form of goto. You usually don't know what functions the functions you're calling are calling. If you programmed without functions, you wouldn't have a problem with invisible exceptions. Which means that the problem is not specifically tied to exceptions, and is not a valid argument against exceptions in general. You could say error codes are faster, you could say monads are cleaner, but the goto argument is silly. – Eva Mar 07 '13 at 01:15
  • @Eva actually, error codes are *slower*, as they need repeated checks after each operation that could fail, including all levels of delegation, whereas an exception can skip over these call chains directly to the handler, while the ordinary code flow is not cluttered with conditionals. In languages where exceptions record stack traces, they are usually slower, but only *when* an exception is created. – Holger Jan 25 '18 at 15:25
  • @Holger... or create them without stacktraces at all? – Eugene Jan 25 '18 at 20:06
  • @Eugene well, when you disable stack traces, exceptions indeed become really fast, but I would still recommend a coding style where exceptions stay the exception, hence, their creation costs are irrelevant anyway. – Holger Jan 26 '18 at 08:35
  • @Holger right, but my understating is that the context is goto vs exceptions here, if so why would I need stack traces? – Eugene Jan 26 '18 at 09:22
  • 1
    @Eugene not exactly. I was just referring to the “error codes vs exceptions” performance comparison. So in both cases we have a normal code flow, in which using exceptions is faster and the erroneous case, in which case exceptions are slower when they record stack traces, which shouldn’t be a problem. If you want to abuse exceptions as some kind of goto, disabling traces would help the performance; I once hotfixed some code of this kind by disabling stack trace for that particular exception, but at some later time I rewrote the entire code to not abuse exceptions, which is even better (to me)… – Holger Jan 26 '18 at 09:36
0

I've read a lot about exception handling, even if (most of the time) I cannot really say I'm happy or sad about the existence of checked exceptions this is my take : checked exceptions in low-level code(IO, networking, OS, etc) and unchecked exceptions in high-level APIs/application level.

Even if there is not so easy to draw a line between them, I find that it is really annoying/difficult to integrate several APIs/libraries under the same roof without wrapping all the time lots of checked exceptions but on the other hand, sometime it is useful/better to be forced to catch some exception and provide a different one which makes more sense in the current context.

The project I'm working on takes lots of libraries and integrates them under the same API, API which is completely based on unchecked exceptions.This frameworks provides a high-level API which in the beginning was full of checked exceptions and had only several unchecked exceptions(Initialization Exception, ConfigurationException, etc) and I must say was not very friendly. Most of the time you had to catch or re-throw exceptions which you don't know how to handle, or you don't even care(not to be confused with you should ignore exceptions), especially on the client side where a single click could throw 10 possible (checked) exceptions.

The current version(3rd one) uses only unchecked exceptions, and it has a global exception handler which is responsible to handle anything uncaught. The API provides a way to register exception handlers, which will decide if an exception is considered an error(most of the time this is the case) which means log & notify somebody, or it can mean something else - like this exception, AbortException, which means break the current execution thread and don't log any error 'cause it is desired not to. Of course, in order to work out all custom thread must handle the run() method with a try {...} catch(all).

public void run() {

try {
     ... do something ...
} catch (Throwable throwable) {
     ApplicationContext.getExceptionService().handleException("Handle this exception", throwable);
}

}

This is not necessary if you use the WorkerService to schedule jobs(Runnable, Callable, Worker), which handles everything for you.

Of course this is just my opinion, and it might not be the right one, but it looks like a good approach to me. I will see after I will release the project if what I think it is good for me, it is good for others too... :)

adrian.tarau
  • 3,124
  • 2
  • 26
  • 29
-2

In my opinion the checked exceptions are a very fine concept. Unfortunately the most programmers who have worked together we me have another opinion so that the projects have a lot of wrong used exception handling. I have seen that the most programmers create one (only one) exception class, a subclass of RuntimeException. That contains a message, sometimes a multi language key. I have no chance to argument against this. I have the impression that I talk to a wall when I explain them what anti patterns are, what a contracts of a methods are... I'm a little bit disappointed.

But today it has become obvious that the concept to have a general runtime exception for everything is an anti pattern. They have used it for a check of a user input. The exception is thrown so that a user dialogue can make an error message out of it. But not every caller of the method is a dialogue! By throwing the runtime exception the contract of the method was changed but not declared, because it was not a checked exception.

Hopefully they have learned something today and will make their checks (which are useful and necessary) at another place. Using only checked exception couldn't solve the problem but the checked exception would signal to the programmer that he implements something wrong.

Rudi
  • 23
  • 2