5 ms·
Checked exceptions I love you, but you have to go
- strlen 17y agoChecked exceptions are probably are of my biggest pet-peeves about Java (erasure and lack of closures/first order functions are the other ones). They create excess verbosity, but what good are they if most code I've seen does this: try { foo.bar(); } catch (FooException fe) { logger.error(fe); } A descriptive crash would be more useful, especially if the exception is thrown as a result of an invariant being violated. Scala is a step forwards in this manner, but now there's the issue of remembering which Java methods (foreign to Scala) rely on exceptions to convey important information (e.g. anything which throws InterruptedException).
- spectre 17y agoMost try-catches are considered boiler plate and are often generated. For example of the default options in NetBeans generates the following: try { foo.bar(); } catch (Exception ex) { Logger.getLogger(InvalidConversionException.class.getName()).log(Level.SEVERE, null, ex); }
- barrkel 17y agoFileNotFoundException is not really a corner case, it's all but unavoidable race. No matter how soon you open the file after verifying its existence, it could have gone away. And the only reasonable thing you can do in the face of it is route the message that the file is missing to the user one way or another, and possibly exit. In that way, it makes sense for a top-level handler, such as at the main() routine or in the event loop in a GUI app, to be the one to handle it, and for all intermediates to pass it up. The fact that most meaningful applications do I/O at some level, means that almost the only routines that can be indicated not to throw this exception or a similar I/O exception, are functionally pure ones, or the ones that implement the aforementioned user notification.
- gnaritas 17y agoWhy would you verify it's existence? Just open it, you either get it or you don't. If you don't then catch the exception and do what you would have done if you'd have checked and it wasn't there. Honest question?
- mkinsella 17y agoOpening a file (or attempting to) is resource intensive and throwing/catching exceptions is sloooow.
- swolchok 17y agoBoth opening the file and checking whether it exists involve a syscall, which dwarfs the overhead of throwing and catching an exception. If you check whether it exists and then try to open it, that's two syscalls.
- swolchok 17y agoOn reflection, it occurs to me that a Sufficiently Smart Compiler (TM) could figure out that you were going to open the file right after checking whether it exists and just call open(2) as the existence check instead of stat(2) and then open(2). This seems to depend on the details of the library implementation as well, though.
- Confusion 17y agoI don't know how many files you open in your applications, but in all of mine, the number is so small that I could not care less about the overhead of an exception.
- eru 17y agoThe slowness of exceptions depends on your language / implementation of you language.
- gnaritas 17y ago> and throwing/catching exceptions is sloooow. That's not seeing the forest for the trees. Unless a specific inner loop of the program shows up in a profiler as the hotspot because of an exception, this just isn't something you should ever worry about in 99% of code. Don't throw out the nice abstractions that make code simple unless you know for sure it's the actual problem, rarely is that the case for throwing exceptions. In this particular instance, I'd say you're just wrong about not using an exception.
- nopassrecover 17y agoRelying on the IDE to know which exceptions can be thrown is nicer I think. The .NET pattern of inner exceptions is nice too (relevant to the article's example, you could throw an NHibernateException(inner exception:SQLForeignKeyViolatedException)). It's nice I guess from a certainty and stability standpoint in Java to know that you won't have an exception crash your system, but even then you aren't going to be sure because some exceptions do crash your system because they aren't checked (e.g. null pointer, array index etc.). In my opinion Java is a dead language anyway. The language's bloat (exceesive boiler-plate required for everything), lack of high-level functionality and general approach to boxing in the programmer mean that new programmers don't want to use it (most will learn it though). The slow initialisation time (JVM problem) and lack of native interfaces (despite the work done here) mean that companies don't want to use it for customer products. For internal apps, I'd wager that the company just wants something that most people know and that is quick to develop in, and while Java has some ground here I think other languages will be making strong headway too, especially when you have some control on the deployment platforms. Java just strikes me as dissapointing now. It is probably single-handedly responsible for us getting over the fear of automatic memory management and GC. Similarly it's had massive influences on virtual machines and easy cross-platform deployment. Just about every CS student in the world knows Java. But right now it has failed to innovate with the resurgent popularity for language functionality, address the issue of bloat or develop on the issues that discourage people actually using it for cross-platform deployment. In the mobile sector it's pretty strong, but Objective-C/iPhone will probably hurt that, and it's only strong because of the JVM's portability. On the web it had the potential to take out flash, but the incredible load time and associated lag of the JVM initialising has killed that chance. Overall, Java is only afloat because it is too big to sink.
- swolchok 17y agoRelying on the IDE to know which exceptions can be thrown is nicer I think. No. If you can't remember what it throws, you can't remember the documentation. If you can't remember the documentation, you don't fully know how to use it properly. Go read the documentation; IDEs are a crutch. EDIT: I'm completely serious. http://docs.python.org/library/ http://docs.python.org/library/ and help() are my best friends, in that order.
- lincolnq 17y agoFundamentally I want to be able to ask my programming language "what exceptions might propagate to here?" Having this ability allows me to make stronger claims that my program is correct, because then I can say that the only exceptions which can propagate to that point are of a type I have decided not to handle (like the filesystem being disconnected) and this can be a strong safety property. I think Java has ruined checked exceptions for the rest of us, because this article makes good points and successfully knocks down Java's exception system. I don't think this invalidates the concept of checking one's exceptions, though! What would I do instead? Since it's always the prerogative of the receiver of a possible exception to rethrow it uncheckedly, then why not allow the type system to promote (/demote) a checked exception to unchecked at the catchpoint, without requiring an actual catch block? Some system like that could reduce the syntax clutter which is the root of the author's beef.
- holygoat 17y agoClojure catches all exceptions from Java methods, rethrowing them as runtime exceptions. In other words, it gets rid of checked exceptions. (It has to, if you think about it.) No type system support... but no catch block, either.
- cmars232 17y agoYou could use RuntimeException as a superclass for your exceptions, or wrap checked exceptions in a RuntimeException. I'll often rethrow exceptions this way when I have to deal with something horribly wrong (like I/O or UI meltdown, etc.) in a place where I have to deal with the checked exception.. This is handled gracefully in the Eclipse workbench as a popup though, YMMV. I would only recommend this as a last ditch effort to appease the Java compiler though, not an acceptable way to handle a common failure mode. As a side note, does anyone else find the pattern (well, I would say headache) of dealing with checked exceptions similar to working with the IO monad in Haskell?
- nostrademons 17y agoI often explain monads to laypeople as "It's a way to abstract away extra information that's passed through the computation, and define arbitrary ways to handle that information." One of the possible types of "extra information" that may be attached are the types of exceptions thrown: see the Error monad. And yeah, monads have most of the same problems that checked exceptions do. Each action in the monad must have the same type; you can't just ignore one of those bits of extra information and declare that it doesn't matter in this context. For example, if your complicated algorithm writes to a log file, you probably don't care in the rest of the program and could just as easily treat it as pure. But the type system won't let you, unless you fall back on cheats like unsafePerformIO. I dunno really what the right answer for this is, but I really like the Erlang philosophy toward errors. "Let it crash, then do something simpler." Instead of trying to enumerate all the ways your program can fail, it just assumes that you will fail sometimes, so you ought to try multiple ways to succeed instead. That requires quite a paradigm shift from the way programmers normally think about programming, though.
- akeefer 17y agoTo me one of the fundamental issues with checked exceptions is that they break encapsulation. There's no way around it: if foo calls bar, and bar calls readFile which throws an IOException, assuming bar is unable to handle the exception itself (which is generally the case) and you want it to be reported up the stack (say, all the way to the web request handler), you have two options: you declare every method in the chain as throwing an IOException, thus polluting a ton of higher-level code with information that should be restricted to a lower layer, or you catch it and wrap it in a runtime exception, defeating the purpose of having that be a checked exception. I think it's really just a fundamental problem with the whole idea, and it's why any attempt to "fix" them will fail: the idea of checked exceptions is just deeply flawed.
- adingwall 17y agoI often wrap checked exceptions in lower level code in higher level checked exceptions. So if I was reading a configuration file I would throw something like ConfigurationReadException and then wrap the IOException in this. Then if I switch to reading the configuration file from a database (for example), I can wrap an SQLException instead of the IOException. Encapsulation isn't broken and I still have checked exceptions.
- amalcon 17y agoCouldn't we just have the compiler automatically figure out this propagation, and then toss a warning if one could ever reach the top level of a thread? I mean, it seems like a much easier problem than ML-style type inference.
- lucifer 17y agocatch (IOException ioe) { throw new MyObjectXYZContractException ("Can't do XYZ", ioe); }
- efsavage 17y agoThe checked exception didn't break encapsulation here, you did. You have alot more than two options, and the two you listed aren't very good ones. If foo calls bar, something might go wrong, and foo should take some kind of action. If bar can't complete because of an IOException, it should throw it (or wrap it and throw the wrapper). Foo now knows that bar may not complete successfully, and can do what makes sense there (throw it's own exception, retry, etc). If foo can't complete because bar didn't complete, it should tell it's caller. If it matters that the reason Foo couldn't complete was an IOException, throw it, otherwise throw a more meaningful exception.
- wvenable 17y agoThe difference between error codes and exceptions are that, for error codes, you must check the result of every function call and method and in some way handle that result. Contrast this to exceptions, where the advantage is that your error handling is centralized. You should throw as much as necessary and catch in a few key places. Checked exceptions ruins that advantage of exceptions -- you're back to writing a whole bunch of buggy error handling code rather than just a few key catches. The result is errors are being hidden, masked, or ignored for absolutely no gain except to satisfy the compiler.
- killpg 17y agoDon't use Java; problem solved.
- JulianMorrison 17y agoThe most important problem with checked exceptions in Java is the way they interact with inheritance. If you could just declare "throws" everywhere, you could at least live up to the ideal of knowing the exceptions to expect. But you can't override and add a new "throws". Substitution principle, yeah, I know. But why did they design Runnable without "throws Exception"?
- vilya 17y agoRunnables don't throw checked exceptions for the same reason that main() doesn't - because there's nothing sensible that could catch it.
- JulianMorrison 17y agoYou can declare main() as "throws Exception".
- JulianMorrison 17y agoFWIW, Scala lets you call java code that would throw checked exceptions - and not check them. The checking is only enforced at compile time by javac.
- vilya 17y agoWhy does everyone seem to think this a black-and-white issue? Checked exceptions are appropriate for some things, unchecked exceptions are appropriate for others. Use the right tool for the job. Some parts of Java's API have made poor decisions in their use of checked exceptions (the close methods on file input streams and database connections, for example), but that doesn't invalidate the concept. Correct use of checked exceptions helps create more solid code with less testing required, because the compiler is able to do checks that would otherwise have to be written into unit tests. Incorrect use of checked exceptions is what leads to all of the objections I've seen listed here.
- mechanical_fish 17y agoWhy does everyone seem to think this a black-and-white issue? You answered your own question. Inappropriate use of checked exceptions is built into the heart of the Java standard libraries, which means that (a) every new Java programmer is taught, consciously or subconsciously, to use them everywhere, at least until the programmer is very explicitly educated about their badness; (b) even experienced Java programmers must deal with them every day, and 95% of the checked exceptions they deal with are an unredeemed pain in the ass, so before long the very sight of one makes you flinch. It's Pavlovian. In a language community where checked exceptions were a completely optional add-on which was only used when appropriate, they might have a much better reputation.
- lucifer 17y agoI typically use 3 categories of exceptions when building frameworks or libraries. Two are unchecked RuntimeException extensions to indicate operating environment issues, and, implementation issues (aka bugs). Finally, if the api semantics seem to indicate it, api level checked exceptions indicating misuse of the api (aka user errors). Typical example are cases where the api semantics require return values which preclude uniform application of an 'error code' as a viable means of alerting user error. I don't believe it is a good practice to throw an unchecked exception in these cases. Both checked and unchecked exceptions have their uses.