Skip to content
Iulian (not Lulian)
Go back

Abstracting exception handlers in Scala

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.

import scala.util.control._

object exceptions {
  import Exception._

  catching(classOf[NoSuchElementException]).opt {
    List().head
  }                                               //> res1: Option[Nothing] = None
}

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:

import scala.util.control.Exception._

object exceptions {
  val xs = List(1)

  catching(classOf[NoSuchElementException]).opt {
    xs.head
  }                                               //> res0: Option[Int] = Some(1)

  catching(classOf[NoSuchElementException]).either {
    xs.head
  }                                               //> res1: scala.util.Either[Throwable,Int] = Right(1)
}

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:

  failAsValue(classOf[Exception])(-1) {
    xs(2)
  }                                               //> res3: Int = -1

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:

  def logError(t: Throwable): Int = {
    println("Error: " + t)
    -1
  }

  catching(classOf[Exception]).withApply(logError _) {
    xs(2)
  }                                               //> Error: java.lang.IndexOutOfBoundsException: 2
                                                  //| res3: Int = -1

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):

  val loggingExceptions = catching(classOf[Exception]).withApply(logError _)

  loggingExceptions {
    xs(2)
  }                                               //> Error: java.lang.IndexOutOfBoundsException: 2
                                                  //| res3: Int = -1

I’ve found this utility class very useful when integrating Scala code with an existing Java codebase, and a good example of DSL design.


Share this post:

Next Post
ScalaSphere impressions