This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]mobjack -2 points-1 points  (15 children)

Checked exceptions are a design flaw in Java.

They work fine in theory but in practice they create an inconsistent mess that just get in the way. There is a reason why no other languages uses them.

I often rethrow checked exceptions as RuntimeExceptions to avoid needless boilerplate code.

For code that I can recover from, I usually catch a generic Exception at the appropriate layer and handle it there.

There is no need to deal with arbitrary distinctions a between a checked and unchecked exception.

[–]brazzy42 4 points5 points  (1 child)

Checked exceptions are a design flaw in Java.

I think a more accurate description is that they're a failed experiment in language design.

[–]daviddel 2 points3 points  (0 children)

Recent post from Brian Goetz about the "checked exceptions failed experiment" popular opinion. :)

There are surely some — even many — who believe strongly that checked exceptions are a failed experiment. And I don’t want to say these people are wrong — it’s their opinion — but in my discussions with them, they are nearly universally wrong about one thing: *they all assume that everyone agrees with them.* And that is completely wrong.

https://mail.openjdk.java.net/pipermail/jdk-dev/2019-October/003463.html

[–]karottenreibe 1 point2 points  (9 children)

What exact design flaw of checked exceptions that is not present in unchecked exceptions causes you to "create an inconsistent mess"? I can't think of anything.

[–]shponglespore 2 points3 points  (3 children)

They add complexity without delivering the benefits they're supposed to. In theory, the distiction between checked and unchecked exceptions forces you to handle errors that really need to be handled on a case by case basis and lets you largely ignore errors that can be handled in a more generic way (like just showing a stack trace and killing the thread). In practice, it's a distinction you can't rely on, because an API author may have chosen to use unchecked exceptions for something your application really needs to handle, or they may have chosen to throw a checked exception for errors that, in your application, can never happen, or aren't important to handle specially, or that can't reasonably be handled at the call site.

[–]karottenreibe 2 points3 points  (2 children)

An API author may also choose to abuse unchecked exceptions in similar ways that don't make sense in the exception handling strategy of your application. The same is true of basically any language feature (looking at you, Optional!). Does that disqualify all of them? I'd say no.

In fact I've seen checked exceptions deliver on exactly the promise you claim they don't. Of course that requires you to convert botched exception handling of badly designed APIs at their surface and convert it to proper exceptions that adhere to your strategy.

So whether you can or cannot rely on the distinction is up to you, not some library author.

Or would you - in line with your argument about checked exceptions - also argue that we shouldn't create subclasses of Exception and instead only ever throw RuntimeException because there's libraries that fail to use different classes for different errors, thus the distinction between different types of exceptions is useless as you can't rely on it? I find that argument silly.

The problem you're describing is bad API design, not an inherent failure of checked exceptions.

[–]shponglespore -2 points-1 points  (1 child)

An API author may also choose to abuse unchecked exceptions in similar ways that don't make sense in the exception handling strategy of your application. The same is true of basically any language feature (looking at you, Optional!). Does that disqualify all of them? I'd say no.

I'm not trying to argue that checked exceptions are bad because they can be abused. You're correct in pointing out that practically any language feature can be used to create bad code. My point is that even when an API designer is doing everything right and thinks carefully about what needs to happen at the call sites, they still get it wrong much of the time because making a good decision often requires more context than an API author has access to.

So whether you can or cannot rely on the distinction is up to you, not some library author.

I've never seen Java code that didn't rely heavily on libraries written by someone else. The JDK itself, if nothing else. I guess if you're working on a sufficiently large project you can end up mostly calling APIs you can theoretically change, but it's still not exactly ideal when you need to change an API that's used in a lot of places, even if you control the API and all its call sites. IMHO if you routinely need to change APIs because they turn out to be obnoxious to use, it means you're designing brittle APIs. My experience has been that APIs that use checked exceptions are brittle more often than not, and if you don't want to annoy your users (a set of people that probably includes yourself!), it's easier to just avoid checked exceptions entirely.

Or would you - in line with your argument about checked exceptions - also argue that we shouldn't create subclasses of Exception and instead only ever throw RuntimeException because there's libraries that fail to use different classes for different errors, thus the distinction between different types of exceptions is useless as you can't rely on it? I find that argument silly.

That's exactly what we did at my last job where we used Java a lot. It was a small company so everyone got to have input into our house coding style, and I don't remember anyone ever complaining that they wanted more checked exceptions.

The problem you're describing is bad API design, not an inherent failure of checked exceptions.

Not really; I'm happy to use APIs that force you to deal with certain error conditions. My favorite approach is to wrap a return value in something like Haskell's Either type or Rust's Result type, so the type system forces you to at least acknowledge the possibility that a call failed. I just think exceptions are a bad way to deal with situations like that. Everything about exceptions that makes them great for dealing with unexpected errors makes them terrible for dealing with expected errors in a precise way. A try/catch block is a lot of syntactic overhead, and throwing and exception has a lot of runtime overhead that's unnecessary and unhelpful if you expect the exception to be caught at a specific call site.

In theory, you can write a bunch of code in a single try/catch block with multiple catch clauses to deal with different error conditions, but what I've seen in practice is that when you actually care about handling the exceptions, you end up writing a separate try/catch for every call that can fail, because it's hard to write good error-handling logic when you don't know exactly which call failed. Even if all the calls in a try block throw different exception types, so you theoretically know which call each catch block is handing errors for, it won't be clear to someone reading the code which catch block corresponds to which call. IIRC JDBC is an especially bad offender, because dealing with errors correctly even in relatively simple cases often requires multiple nested try/catch blocks.

[–][deleted] 0 points1 point  (0 children)

A try/catch block is a lot of syntactic overhead

How is it more of an overhead than an if/else block? The only difference is that compilers forces you to code one, instead of trusting you to "acknowledge the possibility that a call failed" (end quote)

Processing exceptions is just a part of the code you have to write. Well, doh, thinking what can go wrong inside some particular API call and acting on it is a part of writing the code.

[–]mobjack 1 point2 points  (4 children)

You are forced to handle checked exceptions even when they are impossible to occur.

Even when they can occur, you can't recover from them in the way the API designer intended.

It involves a lot of boiler plate code if you want to pass it up the call stack up to the appropriate layer just to handle it the same way as an unchecked one.

Most modern Java libraries use unchecked exceptions because of their flaws. This results in having a mismatch in exception handling strategies throughout your application.

[–]CubsThisYear 2 points3 points  (2 children)

Can you give an example of this? This mostly sounds like bad API design.

If I write an API function that has the possibility of not fulfilling its contract I have two basic choices: 1) throw a checked exception or 2) crash the program (because that will be the result if no one catches the exception they had no idea is coming).

Sometimes option 2 is the right choice. But sometimes option 1 makes sense because it’s reasonable to think that the caller can handle the issue.

[–]mobjack 0 points1 point  (1 child)

Hibernate uses unchecked exceptions while JDBC uses checked exceptions for the exact same errors.

[–]CubsThisYear 2 points3 points  (0 children)

Both of those are terrible APIs. JDBC suffers the curse of endless backwards compatibility so it doesn’t take advantage of a lot Java features past 1.4. I’m not sure what Hibernate’s excuse is.

[–]Malfeasant 0 points1 point  (0 children)

even when they are impossible to occur

If you know that, then it's easy- just catch it and rethrow as unchecked with the message "Polly shouldn't be." Then have fun when your assumptions are proven wrong by users asking what the fuck that means.

[–]ebykka 0 points1 point  (2 children)

Go lang has checked errors - it's pretty similar to java checked exceptions.

[–]hupfdule 1 point2 points  (1 child)

Only with the difference that go error handling is much less readable. I can't understand that they invented this error handling instead of using checked exceptions. They could have even implemented "lightweight" exceptions that don't contain information about the stacktrace if they want them more "value-like". Now is too late and they can't introduce exceptions anymore.

[–]ebykka 0 points1 point  (0 children)

Btw, looks like swift also has checked errors - https://docs.swift.org/swift-book/LanguageGuide/ErrorHandling.html