bad.robot

good robots do what they're told

Scala Exception Handling

We’re very used to Java’s notion of checked exceptions. If we want to force the developer to consider exceptional behaviour then we typically throw a checked exception. The problem is that despite our best intentions, we can’t force the developer to actually deal with the exception sensibly. Java tries to help by forcing a compilation error onto the developer so they at least forced to choose a course of action. The trouble is though it’s all too tempting to swallow exceptions or just rethrow. We tend to either bury our heads in the sand or litter our code with addition noise.

Scala has taken a different approach. Scala has done away with checked exceptions; all exceptions are effectively RuntimeExceptions and so its left to the developer to decide when to handle them. This obviously leads to less noise but puts more responsibility on the developer. Scala makes it easy to avoid the issue but without a clear system wide policy for exception handling, we can still get into trouble.

In a previous post, I’ve described a general approach to understanding when and how to deal with exceptions in Scala or Java. In this post, we’ll take a quick look at Scala’s syntax around exceptions and how pattern matching is employed.

Exceptions

Scala essentially treats all exception types as RuntimeException. This means it doesn’t force you to handle exceptions. Instead, it combines pattern matching with a single catch block to handle exceptions. For example

try {
  val url = new URL("http://baddotrobot.com")
} catch {
  case e: MalformURLException => println("bad url " + e)
  case e: IOException => println("other IO problem " + e)
  case _ => println("anything else!")
} finally {
  // cleanup
}

Any cleanup can be achieved using the finally block as expected. This works exactly the same way as in Java but perhaps a more idiomatic alternative is to use the loan pattern. You can see an example of the pattern in Java form in the ExecuteUsingLock class in tempus-fugit.

Throwing exceptions is done in the same way as Java, as in the example below.

def load(url: String) {
  // ...
  throw new IOException("failed to load")
}

However, anyone calling this method won’t be forced by the compiler to catch the exception. If you intend to call your Scala code from Java however, you can force checked exceptions using the throws annotation but this still won’t affect Scala clients.

@throws(classOf[java.io.IOException])
def load(url: String) {
  // ...
}

Interestingly, Scala treats throw as an expression with a return type of Nothing. You can use it in place of any other expression even though the result wont actually evaluate to anything.

Pattern Matching

Pattern matching is a bit like a switch statement but unlike Java’s switch statement, pattern matching in Scala can be used to match any kind of constant as well as other things (like case objects). It’s not restricted to just primitives and enums as with Java (although Java 1.7 brought String support to switch).

Pattern matching is applied to the exception type when using catch above but it’s also used in its vanilla form. For example, as described in Programming in Scala, we can work out what to have with dinner in the example below.

def accompaniment(dinner: String) {
  dinner match {
    case "fish" => println("chips")
    case "sausage" => println("mash")
    case "sheep" => println("cheese")
    case _ => println("beans?")
  }
}

Notice that there is no need for a break statement and that each match expression results in a value. So we can take advantage of resulting value and rewrite the above to the following.

def anotherAccompaniment(dinner: String) {
  val accompaniment =
    dinner match {
      case "fish" => "chips"
      case "sausage" => "mash"
      case "sheep" => "cheese"
      case _ => "beans goes with anything!"
    }
  println(accompaniment)
}

Conclusion

The whole thing is generally neater than the Java equivalent but as I keep banging on about, we still need to carefully consider where to apply the catch when handling exceptions. When using Scala, it’s even more important to understand where potential exceptions will bubble up and how to handle them as a system wide concern.

More in the Exception Handling Series

Over to you...