Try : Handling exceptions with grace in Scala. [Functional way with Scala]

Hey everyone, it’s time to continue our previous blog on how to make our code more robust, concise and better functionally defined at the same time. Here we are moving more towards Scala and leaving traditional Java behind. We will see new types and their usage along with the benefits we get from them.

This blog will show you the best way in my perspective to be used in order to handle the exceptions gracefully in Scala ( The beloved coding language for everyone here at Knoldus ) . Our methods would only be responsible for either returning the results or the exceptions, i.e. we will not write any try-catch blocks to handle the exceptions within different methods.

You might be thinking by now that we will be talking about the Either type in Scala next to achieve the composition of methods. Although we can do that but its quite different then the desired functionality and we would not use it here due to the following 2 reasons :

  1. Either type works when you are explicitly defining what will be kept within Left (generally depicting failure) or Right (generally depicting success), i.e. your code would determine what kind of exception message will be sent in the Left instance and what return value you want in Right instance.
  2. In order to define the correct message for the exception that might occur, you might want another try-catch block for different exception cases.

Instead of using try-catch blocks all over the code, we should rather work with scala.util.Try to handle all the exceptions in the code. As it is easier to implement, compose and transform. We would see the usage of Try in this block but we are only looking at the ways of handling exceptions in methods that are sequential in nature. If we need to work on concurrent methods that may run on different threads simultaneously, Futures in Scala provides direct exception handling support via recover.

Instead of wrapping your code in a try-catch block, just wrap it within a Try block.

val result: Try[Int] = Try(riskyCodeInvoked("Exception Expected in certain cases"))

result match {
  case Success(res) => info("Operation Was successful")
  case Failure(ex: ArithmeticException) => error("ArithmeticException occurred", ex)
  case Failure(ex) => error("Some Exception occurred", ex)
}

 

Now to explore further the advantages to use Try instead of try-catch block consider the following example :

def riskyCodeInvoked(input: String): Int = ???

def anotherRiskyMethod(firstOutput: Int): String = ???

def yetAnotherRiskyMethod(secondOutput: String): Try[String] = ???

val result: Try[String] = Try(riskyCodeInvoked("Exception Expected in certain cases"))
  .map(anotherRiskyMethod(_))
  .flatMap(yetAnotherRiskyMethod(_))

result match {
  case Success(res) => info("Operation Was successful")
  case Failure(ex: ArithmeticException) => error("ArithmeticException occurred", ex)
  case Failure(ex) => error("Some Exception occurred", ex)
}

 

In the above code we are composing different methods together using transformations on Try type. It removes all the boilerplate try-catch blocks and also allows you to handle all exceptions at one place. If the method riskyCodeInvoked is causing an exception control will not go to anotherRiskyMethod and so forth.

If you are more comfortable with Option type, you can directly use Try like this :

val result: Try[String] = ???

val resultOpt: Option[String] = result.toOption

resultOpt.map{case res: String => info("Operation Was successful")}

 

There are other methods also which are defined on Try type, like recover, getOrElse, orElse, isSuccess, isFailure, Filter etc. Once you get used of it, you might not want to use try-catch blocks ever 😉 so try it out in your code and enjoy the simplicity of Scala.

KNOLDUS-advt-sticker

Written by 

Rachel Jones is a Solutions Lead at Knoldus Inc. having more than 22 years of experience. Rachel likes to delve deeper into the field of AI(Artificial Intelligence) and deep learning. She loves challenges and motivating people, also loves to read novels by Dan Brown. Rachel has problem solving, management and leadership skills moreover, she is familiar with programming languages such as Java, Scala, C++ & Html.

4 thoughts on “Try : Handling exceptions with grace in Scala. [Functional way with Scala]

  1. Thank you for the this blog post. Very nice. I have one point.

    val result: Try[String] = Try(riskyCodeInvoked(“Exception Expected in certain cases”))
    .map(anotherRiskyMethod(_))
    .flatMap(yetAnotherRiskyMethod(_))

    Am I right thinking that .map shouldn’t use anotherRiskyMethod? Risky methods should return Try and these are chained via flatMap to get rid of Try nesting. It can even mislead reader thinking that anotherRiskyMethod is risky because it throws, which would be an anti-pattern.

    1. Hi petr, thanks for the question.
      From the sample code in this blog, what I really meant to show was that you could compose methods using map(), flatMap() and filter() methods. The usage is similar to what you might use with List or Map collection types.

      if `anotherRiskyMethod()` throws an exception it would still be handled by the enclosing Try as we are having a map in between the two methods. It is not necessary for you to write methods returning a Try type itself if you are composing them with other methods of Try type such as `riskyCodeInvoked()` in the sample.

      Although you are right that the best practice would be to use Try as return type for all the risky methods and use flatMap or for comprehension to compose these methods together.

Leave a Reply

%d bloggers like this: