Both of those are "functional-style" error handling. The only difference is the latter lets you specify that it will handle certain exceptions functional-style while leaving the rest to be handled imperative-style, while the former handles all exceptions functional-style, forcing the programmer to rethrow any unhandled exceptions manually.
The main drawback of imperative-style exception handling is that exceptions only propagate one way: straight up the call stack. You have either the option to handle it there in the call stack or let it propagate. It also forces certain variable scoping choices on you. That is very limiting semantics.
In contrast, Trys
are very flexible. They are regular objects that can be stored, shared, aggregated, chained, and handled wherever you like, not just wherever the call stack happened to be when the error occurred. It can take a while to see the usefulness of this.
One recent example from work was we had a list of servers, and wanted to find the first one with a working connection. The API we were working with threw an exception upon an attempt to connect to a down server. The developer who wrote the first draft of this code had a lot of problems with boundary conditions and variable scope due to using try-catch blocks, and asked for help. Trys
made the task very simple by lazily mapping the list of servers to a list of Trys
, then finding the first Success
.
I encourage you to give these libraries a try (pun intended) and see how they can simplify complex error handling. Since learning about Trys
, I haven't seen a case yet that they haven't simplified.