Multiple ways of handling an exception in scala

There are multiple ways of handling an exception in Scala. In this blog, I will explain one by one.

1- Using try/catch/finally

 val tryCatch = try {
  //Code here that might raise an exception
  throw new Exception
} catch {
  case ex: Exception =>
  //Code here for handle an exception
}

val tryMultipleCatch = try {
  //Code here that might raise an exception
  throw new Exception
} catch {
  case ae: ArithmeticException =>
  //Code here for handle an exception
  case ex: Exception =>
  //Code here for handle an exception
}

val tryMultipleCatchFinally = try {
  //Code here that might raise an exception
  throw new Exception
} catch {
  case ae: ArithmeticException =>
  //Code here for handle an ArithmeticException
  case ex: Exception =>
  //Code here for handle an Exception
} finally {
  println(":::::")
  //Code here, will always be execute whether an exception is thrown or not
}

val tryCatchWithValue: Int = try {
  //Code here that might raise an exception
  "NonNumericValue".toInt
} catch {
  case ne: NumberFormatException =>
    0
} 

2. Using scala.util.Try
The Try type represents a computation that may either result in an exception, or return a successfully computed value.
Instances of Try[T] are either an instance of scala.util.Success[T] or scala.util.Failure[T]

The Try has an ability to pipeline, or chain, operations, catching exceptions along the way like flatMap and map combinators.

import scala.util.{Failure, Success, Try}

val withTry = Try("1".toInt) // Success(1)
withTry match {
  case Success(value) => println(value)
  case Failure(ex) =>
    //Code here for handle an exception
    println(ex)
}

val tryWithRecover = Try("Non-Numeric-Value".toInt) match {
  case Success(value) => println(value)
  case Failure(ex) => println(ex)
}


//Try's map,flatMap,fold etc
def inc(n: Int): Int = n + 1

val try1 = Try("abc".toInt)
val tResult = try1.map(f => inc(f)) // The function `inc` will execute when `Try("abc".toInt)` doesn't raise an exception

Try’s recover and recoverWith: Applies the given function f if this is a Failure, otherwise returns this if this is a Success.

//Recover with value
val tryWithRecoverF = Try("Non-Numeric-Value".toInt).recover {
  //Here you pattern match on type of an exception
  case ne: NumberFormatException => 0
  case ex: Exception => 0
}

//Recover with an another Try
def recoverWith(first: String, second: String): Try[Int] = {
  //The code of recoverWith function will execute when `Try(first.toInt)` raise an exception
  Try(first.toInt).recoverWith {
    case ne: NumberFormatException => Try(second.toInt)
  }
}

Note: all Try combinators like map,flatMap, filter, fold, recover, recoverWith, transform, collect will catch exceptions

def compute(number: Int, divideBY: Int): Int = number / divideBY

val t1 = Try("123".toInt).map(n => compute(n, 2)) //Success(61)
val t2 = Try("123".toInt).map(n => compute(n, 0)) //Failure(java.lang.ArithmeticException: / by zero)
def computeWithTry(value: String): Try[Int] = Try(value.toInt)

val r1: Try[Int] = computeWithTry("123")
r1.fold(
  ex => println(ex),
  value => println(compute(value, 2))
)

computeWithTry("123").fold(
  ex => println(s"Exception--$ex"),
  value => println(compute(value, 0))
) // Exception--java.lang.ArithmeticException: / by zero

computeWithTry("abc").fold(
  ex => println(ex),
  value => println(compute(value, 2))
)

computeWithTry("123").map(n => compute(n, 2)) //Success(61)
computeWithTry("123").map(n => compute(n, 0)) //Failure(java.lang.ArithmeticException: / by zero)
computeWithTry("abc").map(n => compute(n, 2)) //Failure(java.lang.NumberFormatException: For input string: "abc")

Note: The combinators catch only non-fatal exceptions Try (see scala.util.control.NonFatal). Serious system errors, on the other hand, will be thrown.

Here you can find complete code

Stay tuned for the next part 🙂

References: scala.util.Try