Skip to main content

Semi-checked exceptions?

Posted by timboudreau on August 13, 2008 at 9:37 PM PDT

I'm out in Seattle visiting my friend Jon - he has bad RSI right now, so I'm helping him out on a project. He told me an interesting idea he was kicking around when he was at Sun in 1997 or so, about how checked and unchecked exceptions should have been done. It needs thinking through, but I think it has some merit.

There are problems with some exceptions - both historical ones - things that should have been checked but aren't, and things that aren't but should have been. For example:

  • NumberFormatException — This is an interesting one. It's not checked. In some applications it probably shouldn't be - the application can go merrily on. In other cases you actually want to handle it
  • MalformedURLException — Every time a MalformedURLException is thrown, God kills a kitten. Seriously, this is an example of hyper-aggressive validation that probably made sense in HotJava, but outside writing a browser, this just clutters people's code horribly.
  • DataObjectNotFoundException — in nine years of writing NetBeans modules, I have never seen this thrown, but my code is littered with tests for it.

Jon's idea is simple and elegant: Allow individual exceptions, by type, to be flagged as checked or unchecked depending on a flag set on the package (if unspecified, you get the default). I.e. the compiler would understand this, and not compile something if an exception could be thrown, but if it had been flagged as unchecked, allow it to compile. Sort of like turning on and off assertions by package, but at compile time.

Anything like this would need a lot more thinking through (for example, if you call into another package with a contradictory setting to yours, what happens?).

But it's an interesting thing to think about (even if it will probably never happen for Java). What do you think?


@patrikbeno Your example is pointless. You've chosen a method that is not defined to throw a checked exception... to illustrate checked exceptions are a design flaw? (nevermind the issue of catching exceptions across threads... which is an issue w/ checked exceptions how???) Still, the arguments against checked exceptions are specious. They base their arguments on checked exceptions being used on "everything" - not where they are appropriate... Based on that argument I could show just about anything is a "failed experiment". Bloody hell, you can find poor design decisions in any language out there... and stop using C# as example unless you can explain to me how, during runtime, a C# code can interact with code in C++ if C# used checked exceptions... Either way... checked exceptions don't cause bad designs... developers do.

@patrikbeno Your code is the design error.

@erdudley and others We have been discussing the issue over the past days in this thread:

One of two things would happen for users of the 'semi-checked' exceptions: 1). Users who hate checked exceptions will turn them off. 2). Users who don't care will leave it at the default (same as now). In the end, the only thing accomplished is attempting to please those who feel checked exceptions are wrong. Will either option, in itself, create more elegantly designed programs? I don't think so. I guess what I'm saying is, I think the arguments against checked exceptions really don't hold water. In other words - it's a matter of opinion and not 'perfect' language design. I'll take either way, it's 6 of one, half-dozen of another...

The Java exception system seem to be a little underthought; I wish we could get rid of the legacy. In detail, there is a missing element in the hierarchy; the exception ought to be partitioned into RuntimeException (unchecked) and CheckedException. The absence of the latter element causes ugly catch blocks that branch on the exception type. In large, I think that the application of a few principles would clarify the exception situation: First, "fail-stop" -- any exception ought to terminate the program, unless the programmer has proved that the exception can be recovered with the program in a consistent state. A natural consequence of this is that all exceptions should be unchecked, so that exception handlers are unusual and carefully-examined pieces of code. Second, the exception type hierarchy is pervasive and ought to be carefully designed. One example of this is the above complaint about the missing CheckedException type. Also, exceptions should be as specific as possible -- in the extreme, each throw should have its own exception type, properly situated in the exception type hierarchy. Catchers would in general refer to a type higher in the hierarchy, but could be refined to the specific leaf type if required. The Spring SQL exception hierarchy (org.springframework.dao.*) is an example of a decent hierarchy, in my opinion. Given that we cannot know, when throwing an exception, the details of how it will be handled, I doubt that a perfect exception hierarchy is possible. This is intrinsic to the use of static types to model exceptions. But we could do better, even within that constraint.

Dah, just commented in your last post how it would be nice with the subject of checked exceptions. I think this is exactly what needs to happen. I mean, we use -Xlint for so many other things, why not have the compiler and IDE flag checked exceptions the same way. That way we can have our cake and eat it too. The single most annoying thing with checked exceptions in Java is how you are not allowed to comment out a a call to a method which throws a checked exception, without also needing to comment out all try...catch related code around. This should presently just cause an unreachabe code warning, not a compile error!

Nice idea, just not completely thought through. . The problem with checked exceptions is two-fold:: (1) how to throw checked exception when you cannot (or how NOT to be forced to catch exception you're not interested in, which is effectivelly the same) (2) how to catch such an exception when you cannot (and this is the problem) . You certainly can force the compiler to ignore thrown checked exceptions. . But the compiler also enforces that you cannot catch checked exceptions that cannot be thrown in a given context. Compiler knows whether such exceptions can be thrown based on the signatures of the methods invoked in a particular guarded block. . Now if you will be able to throw checked exception without being forced to declare this in your method signature, how would the compiler know that your caller's catch(CheckedException){} is valid? . The only solution would be to disable catch-only-what-can-be-thrown feature in the compiler. This would remove one hell-of-a-feature from the compiler, at least if you like checked exceptions (which I don't). . We better get rid of the checked exceptions completely. Crippling them or inventing workarounds makes no sense to me.

Just because your projects don't use check exceptions doesn't mean that others don't. For example, in certain applications (avionics, mechanized control) it makes sense to have checked exceptions available if you need them. However, most applications don't need them. The standard Java libraries should have been designed not to throw checked exceptions of any sort. That would have removed the pain for most people. Don't remove checked exceptions from the language, just from being used in the standard libraries. In your own code checked exceptions are easily dealt with. Don't add a throws clause to your method signature. Instead wrap the checked exception in a RuntimeException and throw that Always remember to 'chain' the original exception so information is preserved. Example: /** * Note: not throws clause. */ void public foo() { try { stream.operation(); // some operation that throws a checked exception. } catch( ex) { throw new RuntimeException("Description of problem (with any relevant data)", ex); } } This is simple, and means calling methods don't need to deal with checked exceptions. I hope this helps some of you.

@erdudley: You are wrong. It is not about like vs. dislike. Checked exceptions are design error. Example: // some interface void execute(Runnable r) {} // using it something.execute(new Runnable() { public void run() { try { createNewFile(); } catch (IOException) { // what will you do? you wanna throw this but you can't (you are implementing Runnable) // just wrap it into some RuntimeException // so fo every CheckedException you should (or you could end up with) corresponding RuntimeException // and guess what? the caller is gonna have to catch your runtime versions } } })

Checked exceptions discourage leaky abstractions.

Checked exception is most stupid java design error. All exceptions just must be unchecked.

I think I'd settle for a VM-wide per-type flag, so I could fix the standard ones that are in the wrong bucket for my project. Another good example is SQLException, which is such a pain that a large part of Spring's success could probably be attributed to them wrapping SQLExceptions in an unchecked exception!