Live data from Hacker News

Unchecked Java: Say goodbye to checked exceptions

github.com

151–160 of 297 posts

Re: Unchecked Java: Say goodbye to checked exceptions

#151
post #82
post #58

Earlier quoted context omitted.

> Checked exceptions however are as safe No. If I add a checked UserNotFound exception to a getUser db call, you can bet someone higher up the stack will do try catch Exception e, so now they're catching OutOfMemory and who knows what else.

As opposed to force unwrapping a Result type? Also, OutOfMemory is an error, exceptions won’t catch it.

Force-unwrapping a Result type is something you can do in multi-paradigm languages such as Rust, but not in stricter functional languages like Haskell - at least not easily (and we're worried about developers taking the easy way out here).

But more importantly, force-unwrapping is not equivalent to catching generic exceptions. Instead, it's equivalent to catching all checked exceptions and wrapping them in a Runtime error. It's also almost equivalent to what this compiler plugin does (or Kotlin or Lombok's @SneakyThrows do).

Catching "Exception" and trying to handle it generically, is more closely equivalent to this type of code:

  match result {
    Ok(value) => doSomethingWithValue(value)
    Err(e) => println("Error: {e}!")
  }

Re: Unchecked Java: Say goodbye to checked exceptions

#152
post #98

Earlier quoted context omitted.

Ugh Lombok! Literally everything it does is replaced by any competent IDE with auto-generated methods, with the added benefit of not requiring special build handling steps because the library can't play by the normal annotation processing rules. There was maybe a time Lombok made sense. It does not anymore. Death to Lombok.

Disagree. Just because the ide wrote a bunch of boilerplate for me at some point doesn't mean I can know the boilerplate is unchanged without reading a bunch of getters and setters. The mental burden of tiny classes is so much nicer to read.

This is every Lombok lover's favorite strawman argument I've run into.

I've been coding in Java professionally for ~20 years. I can count with zero hands the number of times I've been burned by a getter or setter getting changed into something surprising.

If you really need auto-generated getters/setters/builders - Immutables [1] is a library that does it using bog standard annotation processing rules that don't require hacking your build process.

[1] https://github.com/immutables/immutables

Re: Unchecked Java: Say goodbye to checked exceptions

#153
post #55
post #31

Earlier quoted context omitted.

Exceptions are not unsafe. That said, not modelling them in the type system is a mistake. But the model has to be useful - knowing what functions can or cannot throw is useful, knowing what they throw, less so. (They are safe because of try-finally / try-with-resources)

They are unsafe because they invariably result in people either ignoring them or catching more than they should, or less than they should, and the compiler happily lets you do that, EVEN when you're using checked exceptions.

There is no should/shouldn't. If you don't have a specific error in mind and how to handle it, you shouldn't handle it. In practice most errors can be left unhandled all the way to e.g. server response, so this works quite fine. `try-with-resources` is typically awkwardly implemented unfortunately (defer is nicer, the new `using` keyword in JS is quite nice too)

Re: Unchecked Java: Say goodbye to checked exceptions

#154

Earlier quoted context omitted.

Exception based error handling is unsafe when they are unchecked exceptions. Checked exceptions however are as safe as Either, Try, Monads, Applicatives or whatever. You are forced to declare them in your method signature, the caller is forced to either handle them or rethrow them + declare them as well. And I guess this is precisely why so many developers hate them; they don't like the extra work they have to do to…

> And I guess this is precisely why so many developers hate them; they don't like the extra work they have to do to catch all those edge conditions I hate checked exceptions when they force me to handle an exception which I know is impossible given the arguments passed to the method. For example, some older Java APIs take an encoding name and force you to handle the checked UnsupportedEncodingException - even when th…

> I hate checked exceptions when they force me to handle an exception which I know is impossible given the arguments passed to the method.

If I want to ignore a set of exceptions, I have the option to catch(Exception e) {} signaling that I recognize the risks that have been explicitly communicated by the API (that throws). An @IgnoreExceptions annotation would help dump the 5? boilerplate lines.

The unknown risks for other non-specific Runtime exceptions, are not included. I can catch those too if I add a catch(RuntimeException e){}, again signalizing that I recognize the risks such that other developers understand that I'm opting out of handling those conditions, which may or may not be errors in a classic sense. eg an expected socket not being available causing an IOException, because I'm doing some concurrent process.

Re: Unchecked Java: Say goodbye to checked exceptions

#155
post #117

One of the biggest flaws in C#, in my experience, is lack of checked exceptions. As an example, I wrote some very good code, carefully tested it, made it work flawlessly, then suddenly it started crashing. What happened? Someone made a change in a function I was calling, and it started throwing a new exception. This would have caused a compile error in Java, not a crash. More on checked vs unchecked exceptions here:…

Lets be honest. The more likely thing is that either the coworker would use an unchecked exception or that they would change the callsite to: try { theUpdatedFunction(); } catch (MyNewCheckedException e) { logger.warn("Whoopsie doopsie", e) throw new SomeUncheckedException("Something failed, idk", e) } Which really is a zero sum game. The code still breaks the same way, but the checked exception gets eventually wrapp…

> That bug should have been caught by tests, code reviews and good communication.

There's a reason we have compile-time checks. If you think compile-time checks should be replaced with additional tests, code reviews and good communication, then you want a scripting language, not a compiled language.

You do not wrap checked exceptions in an unchecked one... unless you are a really bad Java programmer.

Re: Unchecked Java: Say goodbye to checked exceptions

#156
post #117

Earlier quoted context omitted.

Lets be honest. The more likely thing is that either the coworker would use an unchecked exception or that they would change the callsite to: try { theUpdatedFunction(); } catch (MyNewCheckedException e) { logger.warn("Whoopsie doopsie", e) throw new SomeUncheckedException("Something failed, idk", e) } Which really is a zero sum game. The code still breaks the same way, but the checked exception gets eventually wrapp…

Yep. This is similar to a viewpoint by Anders Hejlsberg and many on the C# team at the time: https://www.artima.com/articles/the-trouble-with-checked-exc... > You see programmers picking up new APIs that have all these throws clauses, and then you see how convoluted their code gets, and you realize the checked exceptions aren't helping them any. And he goes on to elaborate on how this gets more complicated when versi…

Hejlsberg is a terrific compiler writer. Turbo Pascal was awesome! He is not a good language designer, however. The exception mess in C# is the proof. See my comment at the root of this thread.

Re: Unchecked Java: Say goodbye to checked exceptions

#157
post #28
post #20

Exception based error handling is so bad and unsafe that adopting functional error handling with Either, Try etc as implemented by functional addon libraries for many languages, while not yet common, in time it will become the new default even in OO languages. (just like it's been the default in functional languages for decades) Functional error handling types are much simpler, safer and more powerful. Simpler becaus…

Checked exceptions are exactly analogous of Result/Either types. They are just built into the language with syntactic sugar, automatically unwrap by default (the most common operation), can be handled on as narrow or wide scope as needed (try-catch blocks), does the correct thing by default (bubbling up), and stores stack traces ! In my book, if anything, they are much much better! Unfortunately they don’t have a fla…

No, unfortunately they are not. The problem is not with checked exceptions themselves, but with the other type of exceptions in Java.

In languages that rely on Result/Either for error handling, you've got two types of errors: Typed errors (Result/Either) and untyped panics. Typed errors are supposed to be handled, possibly based on their type, while panics can be recovered from ("catched") but these are serious, unexpected errors and you're not supposed to try to handle them based on their type. Since typed errors generally need to be handled explicitly while untyped errors are unexpected, typed errors are always checked (you can't skip handling them), while untyped errors are unchecked (implicitly propagated up the stack if you don't do anything to catch them).

Java has three types of errors:

1. Checked errors, a.k.a. checked exceptions: (exceptions that inherit from Exception, but not from RuntimeException). 2. Unchecked application errors: exceptions that inherit from RuntimeException. 3. Unchecked fatal errors: exceptions that inherit from Error.

These three kinds of errors live in a confusing class hierarchy, with Throwable covering all of them and unchecked application errors being a special case of checked application errors.

Like everything else designed in the early Java days, it shows an unhealthy obsession with deep class hierarchies (and gratuitous mutability, check out initCause()!). And this is what destroyed the utility of checked exceptions in Java in my opinion.

Consider the following example: We have a purchase() function which can return one of the following errors:

- InsufficientAccountBalance - InvalidPaymentMethod - TransactionBlocked - ServerError - etc.

You want to handle InsufficientAccountBalance by automatically topping up the user's balance if they have auto top-up configured, so you're going to have to catch this error, while letting the rest of the errors propagate up the stack, so an error message could be displayed to the user.

In Rust, you would do something like this:

  account.purchase(request).map_err(|err| match err {
    PurchaseError.InsufficientAccountBalance(available, required) => {
      account.auto_top_up(required - available)?
      account.purchase(request)
    }
    _ => err // Do not handle other error, just let them propagate
  })
In Java, you would generally do the following:

  try {
    account.purchase(request);
  } catch (InsufficientAccountBalance e) {
    account.auto_top_up(e.requiredAmount - e.availableAmount);
    account.purchase(request);
  } catch (Exception e) {
    // We need to catch and wrap all other checked exception types here
    // or the compiler would fail
    throw new WrappedPurchaseException(e);
  }
The "catch (Exception e)" clause doesn't just catch checked exceptions now - it catches every type of exception, and it has to wrap it in another type! Of course, you can also specify every kind of checked exception explicitly, but this is way too tedious and what you get in practice is that most code will just catch a generic Exception (or worse - Throwable!) and wrap that exception or handle it the same way, regardless if it was a NullPointerException caused by a bug in code, an invalid credit card number.

The worst problem of all is that once developers get used to write "catch (Exception e)" everywhere, they start doubting the values of checked exceptions: after all, most of their try clauses seem to have a generic "catch (Exception e)", so does it really matter at all of they're using checked exceptions?

This is the reality. Checked exceptions failed in Java. Most Java developers see them as nothing more than a nuisance and look for ways to bypass them. That does not necessarily mean that the concept of checked exception as a language level facility for errors has failed, but it certainly failed the way it has been implemented in Java.

Re: Unchecked Java: Say goodbye to checked exceptions

#158
post #125

One of the biggest flaws in C#, in my experience, is lack of checked exceptions. As an example, I wrote some very good code, carefully tested it, made it work flawlessly, then suddenly it started crashing. What happened? Someone made a change in a function I was calling, and it started throwing a new exception. This would have caused a compile error in Java, not a crash. More on checked vs unchecked exceptions here:…

The trouble with checked exceptions is that they prevent you from easily extending classes or implementing interfaces that you don't control. Your new class might need to throw a checked exception not included in the method signature. So then you have to resort to hacks like wrapping the new checked exception inside a runtime exception.

Not true. Exception hierarchies solve this problem.

Re: Unchecked Java: Say goodbye to checked exceptions

#159
post #76

Earlier quoted context omitted.

It feels like you're trying to use Exceptions as a way to steer your logic, otherwise why would you need to know why an operation failed to such detail? Your controller method cannot act differently on a DBConnectionerror or OutOfMemory error. Not to mention that exceptions cause developers to use them as control flow mechanisms. For example searching a user by id. If the database returns 0 records, is that reason to…

WirelessGigabit gets it. That last fact is huge - functional error handling forces callers to handle (or pass on) exactly what can go wrong, no more, no less. (unlike exceptions)

That's not really true in practice. Often you just end up with a massive Error variant type that's used everywhere, even when the specific function you're calling could only return one of them.

Re: Unchecked Java: Say goodbye to checked exceptions

#160

One of the biggest flaws in C#, in my experience, is lack of checked exceptions. As an example, I wrote some very good code, carefully tested it, made it work flawlessly, then suddenly it started crashing. What happened? Someone made a change in a function I was calling, and it started throwing a new exception. This would have caused a compile error in Java, not a crash. More on checked vs unchecked exceptions here:…

> One of the biggest flaws in C#, in my experience, is lack of checked exceptions. I couldn't disagree more. Checked exceptions in Java have ruined a generation of programmers. The truth is, under checked exceptions, to satisfy the compiler the function that you called would declare that it throws a SomeModuleException and the programmer who wrote that function would put all his code in try/catch block that catches a…

That's how you do it in C#... See InnerException [1]. What a good programmer would do is to throw a new exception, and fix the callers to handle the new error.

https://learn.microsoft.com/en-us/dotnet/api/system.exceptio...

Post reply on HN