Scala offers many ways to abstract and reuse code, but one area where this is not entirely obvious is exception handling. Sure, when it comes to error handling, there are good ways to write elegant code: use Option
or Either
and soon Try
. But when it comes to exceptions, for instance when interfacing with Java code, one has to write tedious try-catch
blocks. In this post I will briefly describe a few utility methods in the standard library that are undeservedly obscure. I got the idea of this blog post when answering this stack overflow question (though my answer is not the most voted, I still think it’s the better solution ;-)).
scala.util.control.Exception
This little utility class and allows the programmer to abstract over common patterns of handling exceptions. Let’s start with some code that catches an exception and converts it to Option
.
catching
loosely follows the builder pattern and constructs a Catcher
object, with user-configurable logic for what to catch and how to handle the exceptions. In our example, we pass an exception type and configure the catcher to convert the result to an option. Obviously, if an exception is thrown the result is None
In exactly the same way we could convert it to Either
:
Canned logic
catching
takes any number of exceptions and it is the most flexible way to use this library, but a few patterns come up often enough to warrant their addition to the standard library:
nonFatalCatch
is, unsurprisingly, a catcher that re-throws fatal errors. Given that the Scala compiler sometimes relies on exceptions for control flow (like non-local returns), it’s a very bad idea to catch any of thoseignoring(e1, e2, ..)
evaluates a block and catches given exceptions (it returnsUnit
, so this can be used only for side-effecting codefailing(e1, e2, ..)
evaluates a block and catches given exceptions, returningNone
if the block throws an exception, wrapping the resulting value in anOption
failAsValue(e1, e2, ..)(default)
catches any of the given exceptions and returns a given default value if the block throws. For instance,
Catchers can be customised even more, and that’s what I used in the SO answer. withApply
can be used to pass a function that handles the exceptional case. For instance:
This example shows how the exception handling logic can be abstracted in a function. We can take this one step further and reuse entire catchers (since they are plain Scala values, there’s not much to be done):
I’ve found this utility class very useful when integrating Scala code with an existing Java codebase, and a good example of DSL design.