> Littering your code with try-catch is what makes exceptions infeasible for error handling.
I honestly don't see the big difference between littering your code with if/else blocks versus littering them with try/catch blocks. Can you elaborate?
If/else provides a clear and easy to follow control flow. try/catch is like a roaming goto that works it's way back up your stack in ways you can't predict.
The context here is Java's checked exceptions, which have to be handled explicitly at the site where they may occur, leading to control flow that - in my view - isn't substantially different from handling errors with if/else.
I don't understand the argument that stack unwinding is unpredictable -- the most naive implementation of exceptions would just be multiple-function returns with automatic propagation (effectively the same as automatically putting the try! macro on every call in Rust).
Good exception-based code shouldn't be littered catch blocks; you only need to catch in places where you can reasonably recover. No matter how complex the application, there are typically only a few places you can meaningfully recover from a real exceptional or unexpected error situation.
Checked Exceptions in Java, for example, force you to litter your code with catch blocks and error handling code that doesn't actually recover from the error. It transforms it. It propagates it. Languages like Go with explicit error handling do the same thing. I don't think that's bad in all situations but often it comes down to what one thinks is an unexpected error for a given project.
I honestly don't see the big difference between littering your code with if/else blocks versus littering them with try/catch blocks. Can you elaborate?