5 ms·
A checked exception is a way for a library to indicate "this is something that can happen and it's up to you to deal with it". It's compiler enforcement so that
by mabbo 8y ago
A checked exception is a way for a library to indicate "this is something that can happen and it's up to you to deal with it". It's compiler enforcement so that your user doesn't see "Exception thrown! <Stacktrace>".
And I think that's a very good thing.
The author, to me, misses the point. Don't rethrow the same exception. Handle it. It you want to handle it by throwing another internal unchecked exception, that's fine- it's certainly one way to handle it. But just modifying your signature so that you don't have to do the work of handling the situation is lazy and a great way to cause yourself bugs.
It leads to some top-of-the-stacktrace method having "catch(Exception e)" where there's little chance you actually know why this exception is happening, what lead to it, what it's about. Your users deserve better than that.
The alternative is that the developer doesn't know all the circumstances they must handle. They may not see a file not found error for years in production. Suddenly an unexpected exception of throwing up and we have to dig through user error reports and stack traces to figure out what happened.
- deleted 8y ago[deleted]
- wtetzner 8y agoI think the problem is that checked exceptions seem to defeat the benefits of using exceptions. You're better off returning something like Rust's Result type.
- gpderetta 8y agoThey are completely equivalent.
- wtetzner 8y agoThey aren't, because you have to use clunky verbose syntax (and try/catch blocks aren't expressions, which makes things worse). Also, there are several limitations on generics with exceptions that don't exist with regular values. My point is that there's no reason to include special syntax/concepts for checked exceptions over just using values.
- EdwardDiego 8y agoI quite prefer the Option monad approach in Scala where you can pattern match the result. Far more succinct and doesn't require program logic flow to be interrupted.
- deleted 8y ago[deleted]
- groestl 8y ago> Don't rethrow the same exception. Handle it. It you want to handle it by throwing another internal unchecked exception, that's fine- No, that's not fine. Typically, the layer immediately wrapping the throwing code has no knowledge about semantics. It's measurement code, logging code, caching code, transaction handling code, batch explode/aggregation code etc, but nothing that could make sense of a FileNotFoundException. The layer that wraps all this infrastructure code has more info, and can make sense of individual exceptions. By wrapping the original exception, this code now has to go on a getCause() safari to find out what happened. And yes, with checked exceptions there is no way around that, and that's the reason they should go.
- mabbo 8y agoI don't mean to wrap it in a generic exception, I mean to wrap it in a context-specific exception written for the purpose. A "UserDoesntExistException", or a "DatabaseNotRespondingException". Something for the purpose that likely exists in a useful hierarchy.
- groestl 8y agoThis is better, but it could have been the original exception all along, given the rare number of cases in real-world code where the call site actually knows how to recover.
- skybrian 8y agoTypically you don't need to catch at this level of granularity. A generic UnavailableException would cover it. The reasons why a method can fail vary by implementation and you typically don't need to expose this at the API level. It shouldn't be a breaking change for a method to fail for a different reason because the implementation changed. If you take this approach, there are two kinds of methods: those that always succeed and those that can fail. It's similar to how Go's error type works. Java is a mess not due to the existence of checked exceptions, but because they created an unfortunate exception hierarchy and that resulted in inconsistent API design where there's no consensus about what to do.
- bluejekyll 8y agoThis is exactly the opposite recommendation I give. Never handle an exception (always rethrow) unless you know that you can do something specific in that exceptional case. In most cases just rethrowing the exception is the correct thing, and many bugs come from people mishandling exceptions. A perfect example is InterruptedException, where really bad things happen if you don’t rethrow that. Just rethrow, it’s generally the best thing.
- kjeetgill 8y agoI think you both generally agree. The choice is either handle now, or rethrow and handle later. Which one is "default" depends on if you're writing library code, application code, or service code. Especially in services rethrow, catch all at the top, and log is common and makes sense. Probably less appropriate for a zlib or a file not found call. You'll have to do something (unless the answer is crash ... Which it is a sometimes!)
- bluejekyll 8y agoUltimately, the thing I most disagree with in the GP is the idea of handling and rewrapping. There a many cases where this would be bad practice.
- kjeetgill 8y agoIt just depends I suppose? Sometimes you rewrap to get an unchecked runtime exception out of it. Sometimes there's context worth adding: new IndexLoadException(ioException, "Is Hadoop down?"). Either way I think the one thing I hate hate hate is, losing stacktraces! Don't throw a new exception without wrapping the old one. I need that info!
- EdwardDiego 8y ago> Either way I think the one thing I hate hate hate is, losing stacktraces! Don't throw a new exception without wrapping the old one. I need that info! This! Throw as many RuntimeExceptions as you like, so long as you include the originating exception.
- zogulus 8y agoThe trouble is they don't scale and are generally just a pain. Especially with how bad they play with lambda expressions.
- paulddraper 8y agoIt really comes down to two things: 1. How exceptional are exceptions? 2. Are committed to providing good language support? If exceptions are the result of programmer error or terrible malfunction, then unchecked exceptions are fine. But in Java, exceptions are fairly common, even for common low-level stuff: read a non-existent file, parse a non-numeric string, look up a non-existent domain name. If you're going with that approach, it makes sense to type and control these. As for language support...Java is interesting. It doesn't have unions in any of its types except for exceptions. But that makes it interesting trying to write generics, e.g. in a very functional approach. In my experience, most functional Java paradigms just don't support any user of checked exceptions and you make all exceptions unchecked.
- EdwardDiego 8y agoThing is - the person who wrote that code doesn't know what I'm doing with it - a recent offending library for me was Jackson throwing an IOException if it can't parse the JSON. Except I knew that it would always be receiving valid JSON because this code was downstream of a Kafka Streaming app whose entire purpose was to validate that the record was valid JSON that conformed to a JSON schema. But the authors of Jackson require me to add a useless catch clause to my code. And seriously, an IOException for unparseable JSON? At least throw an UnparseableJsonException or something. I will write catch clauses for exceptions that could reasonably be expected to occur and are recoverable from - but if an exception does occur, and you can't recover from it, what the hell is the point of a mandatory catch, log, and rethrow? In my experience, 99% of the handling of a checked exception is to catch them, and rethrow in RuntimeException, which shows that the intent doesn't match the reality of how people are programming. But, that said, I'm writing code on the JVM for our own internal apps - we're never going to have a desktop user facing a stack-trace. I think that when Java was developed it was intended to be far more user-facing than it is now.
- register 8y agoI agree that checked exceptions enforce clarity however I absolutely disagree on the fact that the exception should be managed immediatly. Usually exceptions can and must be managed at different levels of the call stack depending on their origin and destination. My experience tells that usually in an application there are just a few sinks that can be used to ultimately manage exceptions raised from different application flows. The pro of checked exception is to enforce exception management the cons is that they require a pedantic management. For unchecked exceptions pros and cons are exactly inverted. What would be ideal is to have a meta-exception management rule system that would allow to specify which exceptions are allowed to pop-up and which must be managed at the class and method level. Is there any language that provides something nearly similar to this?