Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Imagine that the functionality implemented by your method is very important. This functionality should not be needlessly aborted. If so you want to be aware of errors you can recover from, correct? This is why checked exceptions are helpful. It gives you a guaranteed-by-compiler list of exceptions and you can decide which of those you should recover from.


Or I can catch any exception out of the codepath I'm concerned about, examine it to see if it's one of the known set of exceptions I intend to handle, and then either do so or rethrow it.

If there's a benefit to compile-time exception checking over this method, I have to admit I don't see it. But I've also never worked deeply enough with Java to be familiar with the nuances of its exception handling, so that may be why.


The problem is that handling arbitrary errors can be very complex. It's easy to make errors in the error handling code. Especially if the error you are handling never occurs -- because there's no way to test error handling code for an error that never happens.

That's why it is really useful to know when a call can fail, and what kinds of errors you have to expect.

If you always have to add a generic error handler for possible unknown errors, then you'll write a lot of untested, dead code.


> Especially if the error you are handling never occurs -- because there's no way to test error handling code for an error that never happens.

Sure there is. Find the way it happens, do that, and test that the handler does what it's supposed to. Or, if you can't do that, mock the error.

I suppose that's not guaranteed to be straightforward in Java; it's been a long time but I seem to recall libraries being provided in compiled form, without sources, and it therefore not always being possible to identify the conditions that need to be set up in a unit test. If I recall that correctly, it makes me very glad I no longer use the language.

> If you always have to add a generic error handler for possible unknown errors, then you'll write a lot of untested, dead code.

The generic handler in this case is

    else {
      throw error; // rethrow
    }
You're not wrong that there's value in knowing what exceptions can be thrown at a given point in code. But, as I mentioned in another comment, that's something that can in the general case be known through static analysis, and should. In fact, the Java compiler must already be doing something substantially similar to that analysis for checked exceptions to work at all! Looking for throw statements rather than "throws" declarations seems like it shouldn't be that much more difficult, and I think the burden on Java developers could be substantially lightened thereby in that "throws" declarations would no longer be required.


Checked exceptions give you, essentially, syntactic sugar for handling just a few kinds of exceptions and re-throwing the rest.

It's useful when there are one or two error cases you want to retry or handle specially, but you want to just barf any other error up the stack. It's a specific use case but it's prevalent.

The downside is that sugar can only separate your error conditions by Java type. If everything is just an Exception, you'll have to use sort out your error cases in code.


By the sound of it, that's more like syntactic salt, or maybe syntactic thallium - `else { throw error; }` seems much simpler by comparison.

Being able to know what exceptions can possibly be thrown at a given point is useful, but seems like a problem better solved through static analysis than by requiring annotations.


Yes. But it’s not as simple as checked=good, unchecked=bad and vice versa.


This is one of the main reasons why I personally try to avoid exceptions and instead encode failure into the type system. For example, returning a Result<'t,string> rather than just a 't. (You can refine the type further). Altough, in most languages that approach results in a lot of boilerplate.

In F# it works quite well, though.


How is this different in practice? Checked exceptions are simply "syntactic sugar" for error types (exception objects with a few special handlers to return them and receive them).

You can write almost exactly the same code with your Result by ignoring the error until the point you would catch it with exceptions.

The only difference is that exceptions bubble up if unhandled, which requires a generic catch to match code ignoring errors otherwise.


> How is this different in practice?

It is quite a bit more explicit in that something can have an error and in what ways it can error (if you enrich the type in that way), while still being ergonomical. And it reserves exceptions for the truly unexpected/exceptional cases.


Are we comparing the same things? Adding exceptions to the method signature is pretty explicit to me too.

It's also pretty ergonomical depending on how you generally treat errors you don't care about.

I do find your point about exceptions being for unexpected things interesting: basically, split errors into two classes and use separate mechanisms for each.

I generally feel that this differentiation would never hold between different codebases (an HTTP library may consider network error something "normal", but users of that library might consider it exceptional), but it's surely an interesting concept.

I also think that we as developers are pretty bad at handling both expected and unexpected errors, so having two mechanisms will only make us less likely to do so (not by much, though).

FWIW, my take is that they are largely equivalent except for more or less syntactic support for the approach.


> FWIW, my take is that they are largely equivalent except for more or less syntactic support for the approach.

Yeah, as with lambda calculus and turing machines, they are equivalent in capacity.

> Are we comparing the same things? Adding exceptions to the method signature is pretty explicit to me too.

Maybe, maybe not. IME the IDE support for exceptions is quite a bit worse than for returning results and such.

> I do find your point about exceptions being for unexpected things interesting: basically, split errors into two classes and use separate mechanisms for each.

> I generally feel that this differentiation would never hold between different codebases (an HTTP library may consider network error something "normal", but users of that library might consider it exceptional), but it's surely an interesting concept.

Isn't the two ways to handle it already a thing with checked and unchecked exceptions, though? As in having wrappers that convert one to the other.

> I also think that we as developers are pretty bad at handling both expected and unexpected errors, so having two mechanisms will only make us less likely to do so (not by much, though).

I don't quite agree with that, as with encoding it in the type system conveys more intentionality than with exceptions, IMO.


> I don't quite agree with that, as with encoding it in the type system conveys more intentionality than with exceptions, IMO.

Sure, but why keep using exceptions then at all? I am fine with returning errors making them explicit, but I would avoid exceptions everywhere (Go-style).


Because of interop necessity, mostly (As with f# which has exceptions because .net and c#).




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

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

Search: