I struggle with this one because exceptions are a perfectly good solution. The compiler will tell you when you are not handling a failure case. And if exceptions are unchecked, then you won't get a compiler warning but at least failures will be obvious at runtime.
Why push java towards this 'failures as return values' when we already have a solution? Yes, you will be able to get the compile-time safety by immediately using switch on the return value, but what if you don't? Exceptions are a completely sound solution, failures as return values can easily escape detection.
No-one likes having to think about the error cases, it feels like it complicates things. But we need to stop seeing exceptions/try/catch as something to eliminate and realise that this approach is one of the best innovations of Java. Using return values, or monadic approaches to error handling, are fundamentally unsafe when you have a mixed paradigm language. Far too easy for the programmer to do something wrong, so we're relying on discipline again and not the compiler. In other words, back to square one.
I see. Yes, deliberately ignoring the result and error might be a problem. Of course the same novice programmers could write:
try {
failableCall();
} catch (Throwable t) {
/* Ignore. Stupid Java, always forcing me to handle checked exceptions that won't happen in practice. */
}
In general, I'd say the choice between exceptions and a result-or-error return type should be driven by how likely the user of the method is interested in the return value. In the specific context of this discussion, there is no reason to call a future's get method unless you're really very interested in what it returns. So in this case I'd think the result type would be a good choice. For other APIs the trade-off is different.
I'd say between a stupid result out of ignorance or risky defaults, vs a stupid result out of explicitly being stupid and overriding sane defaults, the latter is probably safer.
Also, exceptions (particularly checked ones) are not a simple matter of optional checks; they form an explicit contract forcing you to deal with exceptions (and having to be explicitly stupid to make them useless via an empty try/catch block). Compare to type-contracts where you'd need to go out of your way to make the "Null" part of the union type "useful" in the first place, for example.
Why push java towards this 'failures as return values' when we already have a solution? Yes, you will be able to get the compile-time safety by immediately using switch on the return value, but what if you don't? Exceptions are a completely sound solution, failures as return values can easily escape detection.
No-one likes having to think about the error cases, it feels like it complicates things. But we need to stop seeing exceptions/try/catch as something to eliminate and realise that this approach is one of the best innovations of Java. Using return values, or monadic approaches to error handling, are fundamentally unsafe when you have a mixed paradigm language. Far too easy for the programmer to do something wrong, so we're relying on discipline again and not the compiler. In other words, back to square one.