Reading Time: 3 minutes

Error handling in Scala can just be written like Java. Put in a little bit of pattern matching magic and you are done. However, given a little use of Scala built-in terrific beauties it can be made much better. Let us have a look.

Let us look at a quick example

def sayHello(any: Any) = { any match { case x: String => "Hello" case _ => throw new Exception("Huh!") } } //> sayHello: (any: Any)String def letMeSayHello = { sayHello(12) } //> letMeSayHello: => String letMeSayHello //> java.lang.Exception: Huh! //| at SomeThing$$anonfun$main$1.sayHello$1(SomeThing.scala:11)

So we have a method called sayHello which misbehaves when you do not pass a string to it. If you call it without a string, it blows up and hence the letMeSayHello invocation blows up as well.

Ok, now traditionally we have been so used to try catch blocks that we put them around.

def sayHello(any: Any) = { any match { case x: String => "Hello" case _ => throw new Exception("Huh!") } } //> sayHello: (any: Any)String def letMeSayHello = { try { sayHello(12) } catch { case e: Exception => "It's Ok if you dont want to say hello" } } //> letMeSayHello: => String letMeSayHello //> res0: String = It's Ok if you dont want to say hello

Ok, so far so good. So we can really write Java in Scala 😉



Now let us see a better way (Idiomatic way!) of handling this

Scala comes with something called a Try. The Try type represents a computation that may either result in an exception, or return a successfully computed value. It’s similar to, but semantically different from the scala.util.Either type. Instances of Try[T], are either an instance of scala.util.Success[T] or scala.util.Failure[T].

Interesting, let us see how our code changes now

import scala.util.Try def sayHello(any: Any): Try[String] = { Try { any match { case x: String => "Hello" case _ => throw new Exception("Huh!") } } } //> sayHello: (any: Any)scala.util.Try[String] def letMeSayHello = { sayHello(12) } //> letMeSayHello: => scala.util.Try[String] letMeSayHello

So, we put a Try block around out sayHello method code. Now the method, letMeSayHello does not need to do explicit error handling. It gets back either Success(“Hello”) or Failure(java.lang.Exception: Huh!)

In the above scenario, it would get Failure(java.lang.Exception: Huh!) and you would be able to extract the value with

letMeSayHello.isSuccess //> res0: Boolean = false

Now, there are various ways of dealing with this. You could pattern match on the boolean and take an action like

val result = letMeSayHello //> result : scala.util.Try[String] = Failure(java.lang.Exception: Huh!) if (result.isSuccess) result.get else "who cares"//> res0: String = who cares

OR you could simply do a getOrElse

val result = letMeSayHello.getOrElse("who cares") //> result : String = who cares }

OR you could let the letMeSayHello method handle the success and failure

def letMeSayHello = { sayHello(12) match { case Success(result) => result case Failure(result) => "who cares" } } //> letMeSayHello: => String letMeSayHello //> res0: String = who cares

OR you could get even fancier ! I like this one. The awesome recover mechanism

def letMeSayHello = { sayHello(12) recover { case e: Exception => "who cares" } } //> letMeSayHello: => scala.util.Try[String] letMeSayHello.get //> res0: String = who cares

The recover allows you to recover in case of failures with an alternate condition that you would want to execute which results in a success. Hence, in this case, we mentioned that either we would get a success by default or we would convert the error into a success scenario by writing a recover block so that we can confidently call letMeSayHello.get

You can find the gist here, on the Knoldus GitHub account. Have fun!