Hacker News new | past | comments | ask | show | jobs | submit login
RuntimeExceptions – To try-catch or not to catch? (10kloc.wordpress.com)
27 points by perseus323 on March 9, 2013 | hide | past | favorite | 21 comments



Sorry, this is not going to be gentle.

This post is clearly written by someone who is new to Java, and starts with the antique assumption that the runtime/checked exception dichotomy is a good idea. After nearly two decades of experience, programmers and language designers have resoundingly voted this language design feature to be a failure. A little bit of experience catching idiotic exceptions like UnsupportedEncodingException and you start to see why. But it goes deeper than just bad design in the standard libraries - checked exceptions fundamentally violate interface encapsulation - try throwing a meaningful exception through Runnable or Iterator. The net result is stacktraces with dozens of wrapped exceptions that destroy any hope of meaningfully handling known error conditions.

Stop it. JUST STOP IT. Checked exceptions have wasted hundreds of hours of my time, not just writing lame wrappers so that I don't have to type try/catch on every line of code, but also by making debugging and error handling five times more painful than it should be.

If you're still touting checked exceptions in 2013, you are part of the problem. Stop it. Java needs to evolve, and your fresh-from-1995 opinion is not helping.

TL;DR: Of course you should catch RuntimeExceptions. There should be no other kind of exception.


> checked exceptions fundamentally violate interface encapsulation

You have that backwards. Unchecked exceptions will blithely and without warning completely explode your stack. They're the Atomic Goto.

The only way to know whether you're going to get one is to check the documentation, where you can only hope that the API author -- and the author of every API he calls -- has actually documented the exceptions that get thrown, because the compiler will be no help whatsoever, and god forbid an API start throwing an exception later.

> ... try throwing a meaningful exception through Runnable or Iterator.

If you pass around an object that conforms to Iterator, but throw an exception within it, __YOU'RE BREAKING THE API CONTRACT.__

Anyone that relies on the API contract of the Iterator class could have their state completely walloped by the Atomic Goto you inserted with a runtime exception.

> Stop it. JUST STOP IT. Checked exceptions have wasted hundreds of hours of my time, not just writing lame wrappers so that I don't have to type try/catch on every line of code, but also by making debugging and error handling five times more painful than it should be.

This makes no sense, because more work is required without checked exceptions.

Without checked exceptions:

- You must check the API docs for every line of code you write to see if it will throw an exception, and if so, what types.

- If it throws an exception, you must either add a try/catch block to handle the error appropriately (or wrap it in a new exception type), or you must add documentation to your method to declare that it will bubble up an exception, and of what type.

- If new exception types are thrown by underlying code, nothing tells you until your application explodes.

With checked exceptions:

- The compiler tells you what exceptions code throws, and of what type.

- If it throws an exception, you must either add a try/catch block to handle the error appropriately, or declare it in the method prototype. The IDE will do both of these things for you.

- If new exception types are thrown by underlying code, the compiler will warn you.

> If you're still touting checked exceptions in 2013, you are part of the problem. Stop it. Java needs to evolve, and your fresh-from-1995 opinion is not helping.

Stop advocating broken API design and ignorance of API invariants.


I will try to follow the HN ethos and give you the benefit of all the doubt I can. I have to admit, as someone who has been working with this language since the beginning, it's a deeply frustrating struggle. This debate is a microcosm of exactly what went wrong with Java, and why "kids these days" are abandoning it in droves. Have you noticed that all the post-Java languages, from C# to Ceylon, abandon this misfeature?

Point by point:

Unchecked exceptions will blithely and without warning completely explode your stack.

No. They rewind back to the level at which you catch the appropriate exception - possibly Exception. It's true that you aren't always able to catch each exception as specifically as you want. But at least you have a hope of doing that instead of catching RuntimeException and searching back through a dozen nested exceptions, which is today's reality.

In actual practice, there's usually a place you can (and should) catch Exception so that you can log and either retry or abandon the unit of work. In the context of a web server, this is usually "one request". That's why your appserver doesn't crash when something goes wrong.

This isn't theory, your appserver already does this, and it's a wonderful thing. Try doing some node.js programming sometime for a taste of what it's like without that.

Your mistake is believing that there is an alternative to RuntimeException. There is not.

If you pass around an object that conforms to Iterator, but throw an exception within it, __YOU'RE BREAKING THE API CONTRACT.__

Again, your mistake is believing there is an alternative. With the exception of very simple classes, all code has exceptional conditions. Do you create DatabaseIterator which throws DatabaseException (and NetworkException) every time you want to iterate a result set? Then you can't use it with Guava or any of the other 10 million Java libraries that consume standard interfaces, and you might as well not have interfaces at all.

Only pedants care if the compiler checks every single exception. Real-world programmers expect that code will complete normally, and catch exceptions at a high enough level that they can do something useful about it (eg, retry or return an error code to the client).

Exceptional conditions cannot be part of the API contract, because every body of code has different exceptional conditions, and if you try to account for them, you have one of two results:

* You give up on standard interfaces completely. You have DatabaseIterator (which doesn't extend Iterator), FileIterator (which doesn't extend Iterator), etc.

or:

* You throw IteratorException from each method. This is what the Java SDK ends up doing in various places (eg, InvocationTargetException) which is just plain retarded. It would make more sense (and be less annoying) to just throw Exception and leave off the wrapper exception.

You must check the API docs for every line of code you write

Sorry, you are not excused from this, ever. At least with exceptions, you have the option of ignoring the problem at deep levels and catching them higher up - which you already have to do anyways, because nobody wants their app to crash at the first exception. In webapps or appservers it's at the request level; in GUI apps it's usually the UI event handler.

With checked exceptions:

No, the compiler doesn't do any of that shit. Because in the Real World, you end up passing data through a standard interface and the exception gets wrapped. Don't believe me? When was the last time you saw a stacktrace that wasn't wrapped with several Caused by clauses? With the exception of remote API calls (where the exception class may not exist on the client), Caused by: is a fundamental failure of language design. There's no sane reason for this construct to exist. Try writing code in other languages and feel how refreshing it is to get clean stacktraces. You don't even have to leave the JVM, you just have to use any of the languages designed since 1995.


I am having a lot of trouble giving you the benefit of the doubt, since what you seem to be arguing for is leaving API contracts completely ambiguously defined because it's too much effort for you to do otherwise. You're not arguing for correctness, or for reliability, but rather for your own convenience in the face of something you find burdensome. That is uninteresting to me.

This subject has been hashed to death, we're repeating the same arguments. You want to leave things ambiguous, I want to ensure that behavior is well-defined.

You're right that this has been abandoned by other languages. In many of those languages -- including Scala -- you can make use of Either/Option monads to achieve the same effect without exceptions at all. In others, you just have to either expend a bunch of mental effort to ensure you code defensively, or take your approach of spinning the chamber and hoping for the best.

Your argument for "well defined points" only begins to make sense in purely functional languages. Otherwise, there's no way to guarantee a lack of side-effects in your use of atomic-goto, and the result is invariably that the software is unreliable and prone to strange stateful failure.


Working with the org.json.JSON classes is what made me switch my mind about the use of checked exceptions. Catching these checked exceptions makes no sense at all.


That API in particular has 'opt' variants of its accessors that return NULL rather than throwing an exception.

That said, a standard clean usage model for the checked variants would be to declare a 'throws' from your JSON parsing code, and then at a higher level wrap that in an InvalidMessageException or similar. The non-checked approach would be to check for NULLs and ensure that none escape your parsing code.

The only time the checked version becomes burdensome is if you don't encapsulate your JSON -> app model parsing in a single place, and instead sprinkle the code with unencapsulated JSON parsing. In that case, I believe the problem is a lack of encapsulation, not the checked exceptions -- the exceptions just highlights that one is not separating concerns between code that must be aware of parsing issues and potentially invalid data, and code that can be guaranteed to only operate on valid and whole data.


"This post is clearly written by someone who is new to Java"

That was uncalled for. But, since you've decided to immediately call into question people's credentials, let me start with mine. I've done a little over 30 years of software development, and in that time I've programmed in no less than three assembly languages, several BASICs, Pascal, C, C++, JavaScript, dabbled with C#, dabbled with Go, dabbled with Python, been subjected to some Perl and PHP, etc. I'm not God's Gift to Software Development, but I think I have enough experience that my opinion on this matter shouldn't be discarded as uninformed.

"and starts with the antique assumption that the runtime/checked exception dichotomy is a good idea."

I hope you're aware that you're begging the question. In any case, I think checked exceptions are fantastic.

1. The "burden" of dealing with them is minuscule, especially when using modern IDEs. It takes just a few clicks or key presses to add try/catch blocks or re-throw exceptions as necessary. You don't even have to waste time looking up documentation (which may be wrong or even nonexistent). Your tool-chain (IDE and compiler) handles the mundane details for you.

2. It forces developers, who are often hurried, and who often make mistakes, to think about things that could go wrong, and deal with them (one way or another). Oh, sure, you see plenty of "catch (Exception e)" style abuses, but that particular "code smell" is so strong (i.e., easily identified) that it can make code reviews (personal and public) easier. Code reviews in languages with only unchecked exceptions are much more difficult and time consuming.

3. Checked exceptions speeds development. Much less time is spent reading and re-reading API documentation to make sure you've caught all the possible exceptions that might be thrown (so that you can do things like produce meaningful error messages or log entries based on the exception thrown).

4. Unchecked exceptions are a production run-time nightmare. My anecdotal but extensive experience is that languages with only unchecked exceptions cause far too many costly (in both time and money) production headaches. Never, ever defer until run-time, errors that can be caught at compile-time! Admittedly, it could be that my application domain colors my opinion here (I work on large systems, not small systems).

The best argument I've heard against checked exceptions is that they "bloat the code". It's true: checked exceptions requires more code. But I'm writing code, not poetry. My job is to get the implementation right (which checked exceptions help me do) and to write reliable and robust software. Developers who put more emphasis on writing pretty code (sorry, "highly expressive") might want to consider becoming artists instead, where they can fashion "pretty" creations to their heart's content.


Apologies in advance if my comments below sound a bit harsh but I consider your arguments for using checked exceptions non-sense.

"It forces developers, who are often hurried, and who often make mistakes, to think about things that could go wrong, and deal with them"

Checked exceptions won't solve your problem here at all. If you need an instrument to force developers to think about things that could go wrong your team is screwed anyway.

"Much less time is spent reading and re-reading API documentation to make sure you've caught all the possible exceptions ..."

You are never ever going to catch all possible exceptions anyway (runtime exceptions and errors are still there even if you'd prefer to have checked exceptions only).

"Unchecked exceptions are a production run-time nightmare."

And you have to deal with them even if you use checked exceptions (again runtime exceptions and errors are still there). You have to have proper (unchecked) exception handling in the right places in your software.

Are you actually properly producing tests for your code before deployment-time ? Otherwise I would not get it why it would be nightmare.

"The best argument I've heard against checked exceptions is that they "bloat the code". It's true: checked exceptions requires more code.

Bloat causes development drag and makes the code more difficult to understand (more scrolling, jumping to different locations in the same file, etc.).

"But I'm writing code, not poetry."

I think you produce both.

I'd compare here checked exceptions to unchecked exceptions like what staticlly typed languages are to dynamically typed languages. And I've seen a lot of developers "loving" statically typed languages because the compiler tells them all their errors (at least they think so).


"Checked exceptions won't solve your problem here at all. If you need an instrument to force developers to think about things that could go wrong your team is screwed anyway."

It isn't about needs, it's about programming languages making it easier to write robust and reliable software. This benefits all developers, from inexperienced to masters. Even the best developers make mistakes and sometimes forget to check return codes.

Checked exceptions are just one useful tool in the toolbox. Another useful tool is dynamic strings (so that developers don't have to waste wetware cycles worrying about overflowing fixed size string buffers). Another useful tool is garbage collection (so that developers don't have to waste wetware cycles worrying about where and when to free memory).

These features lead to higher productivity and more reliable and robust software. Why wouldn't you want a tool that makes sure you check your return codes? Because it might force you to write "throws FooException" on your method signature, if you choose to handle that higher up the call stack? Oh, what a burden!

"You are never ever going to catch all possible exceptions anyway (runtime exceptions and errors are still there even if you'd prefer to have checked exceptions only)."

This is not a good argument against checked exceptions, this is an argument for using the appropriate type of exception for your current needs. Checked and unchecked exceptions are both useful tools.

Yes, sometimes developers use checked exceptions when they should use unchecked exceptions, and vice versa. And sometimes people use a big screwdriver when they should be using a hammer. Does that make screwdrivers or hammers useless?

"And you have to deal with them even if you use checked exceptions (again runtime exceptions and errors are still there). You have to have proper (unchecked) exception handling in the right places in your software."

I think you may simply be unfamiliar with when checked exceptions should be used, and when unchecked exceptions should be used.

Unchecked runtime exceptions represent conditions that, generally speaking, reflect errors in your program's logic and cannot be reasonably recovered from at run time; i.e., a bug in your program that will require code changes to fix. Generally speaking, you don't catch unchecked runtime exceptions, you allow them to bubble up to a high level handler. The high level handler will log the error and inform the administrator something went wrong, or display a (possibly localized) message to the user indicating that something went wrong, possibly requesting that they allow an error report to be sent to interested parties, etc.

Checked exceptions represent invalid conditions in areas outside the immediate control of the program (invalid user input, database problems, network outages, absent files). Generally speaking, you handle checked exceptions immediately (or almost immediately) and don't allow them to bubble up to a high level handler. These generally do not represent program bugs that require code fixes, it's just mundane but also important stuff your program logic should handle. By throwing checked exceptions in these cases, you eliminate a lot of burden on the caller to make sure they are handling all reasonable conditions.

"Are you actually properly producing tests for your code before deployment-time ? Otherwise I would not get it why it would be nightmare."

Not every code path is reasonably testable, plus tests are often the first thing to go during a crunch. Despite the best intentions, tests are not a cure-all. For best security, use multiple layers. For best software, use multiple layers. Checked exceptions are one of those layers: help your caller do the right thing, enforced by the compiler itself. Sure, tests are great, too.

"Bloat causes development drag and makes the code more difficult to understand (more scrolling, jumping to different locations in the same file, etc.)."

Since in real code you want to always handle return codes anyway, checked exceptions introduce no unnecessary bloat.

"I think you produce both. I'd compare here checked exceptions to unchecked exceptions like what staticlly typed languages are to dynamically typed languages. And I've seen a lot of developers "loving" statically typed languages because the compiler tells them all their errors (at least they think so)."

At this point I'm fairly certain your misunderstanding comes down to not knowing when and where to use checked exceptions, and when and where to use unchecked exceptions. You're conflating all exceptions into one gigantic indivisible entity and asking, "Why have both?" The answer is: because they're used for different things! I hope I've sufficiently answered that in more detail above.

I'm in favor of static typing over dynamic typing as well, but that's a whole other kettle of fish. However, I'm gratified to see that the wider developer community is finally accepting that static typing can be done in such a fashion that it's just as powerful and expressive as dynamic typing, but without what many consider unnecessary bloat or limitations. Languages will continue to evolve, and I'm confident static typing will win.

All of the above is colored by my application domain (I work on server applications that must run flawlessly for at least weeks, usually months, or even years at a time). Robustness and reliability is at or near the top of my list of requirements for a programming language. Different application domains may trade robustness and reliability for other things, which might make sense for those particular application domains.

Checked exceptions make my life much easier and result in more robust and reliable software, because I simply can't forget to check for things like "file not found" or "connection refused" or "invalid user input" -- my tools makes sure I do that. Thanks, tools!

(However, as a user as well as a developer, I wish all developers put robustness and reliability first.)


I think it's normal to catch RuntimeExceptions at a high level in your outer loop so you can log it, email it, or whatever, and not let your process die. This is what servlet containers like Tomcat are doing. I agree that catching them elsewhere raises suspicions.

The author's example seems fine, provided they can distinguish an exception-from-a-B-transaction vs an exception-from-a-program-bug. If I were him, I'd keep that checkFormat method, but only call it when I catch a RuntimeException, to see if it's something to worry about or not.

I was pleased that the author appears to have tested the performance of both approaches and is making a decision based on real numbers.


I'd love to be able to say I never have to catch RuntimeExceptions, but that would require that library and framework writers actually use checked exceptions when they should. The best example I can think of (and one that a JEE developer who uses JPA should be intimately familiar with) is that that the getSingleResult() method of the Query object in JPA throws RuntimeExceptions if zero or more than one result is returned.


The funny thing is, in almost any discussion about exception handling in Java, I hear the opposite complaint - too many APIs throw checked exceptions. I've been leaning more and more to liking it when APIs force consumers to at least be aware of known error conditions.

Scala's Option type is another example of this - I've watched people be sort of annoyed by it at first, but it tends to really improve the reliability and overall quality of the code when it is used properly.


Scala's Option is a monad, so it's very easy to chain several actions and safely decide if they all succeeded or failed. It doesn't compare with checked exceptions at all.


Reliability on prod is imho a big win for the less-sexy checked exceptions.


And that's just one example amongst thousands of others :(

javax.xml.ws.WebServiceException is also quite commonly annoying.


In "real life" you catch runtime exceptions everywhere, because well, that's what third-party libraries often throws. I hate that, especially when these exceptions occurs in prod...


Runtime exceptions can turn into ugly production problems. I prefer a combination of Validation, Success/Failure, Some/None and checked exceptions.


I strongly agree that runtime exceptions are the right way to go for certain rare events, see for example the new Java 8 addExact and multiplyExact methods which throw exceptions on overflows. These will not happen often but making them an exception allows implementers of languages with numeric type promotion to remove their own checks, and for the JIT to optimise the entire exception away in most cases.


Of course, there are also the RuntimeExceptions that should really have been just Exceptions. These are often thrown by libraries where new features required exceptions to be thrown, but they couldn't be checked exceptions because the interface had to remain backwards compatible...

Or, of course, libraries written by people who just don't like checked exceptions at all.


It seems that the debate about using checked or unchecked exceptions is still running.

This article has some more insights I think http://jyops.blogspot.se/2012/03/why-should-you-use-unchecke...


Awesome post. Thanks for posting. This was my interview question.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: