1. Overview

In this tutorial, we’ll learn how to handle multiple exceptions together in Scala. This helps us provide the same error-handling treatment to different exceptions.

2. Handling Exceptions

Exception handling is the mechanism to deal with exceptions in our Scala application. The most common approaches to deal with exceptions are either by using the Java-style trycatch or the most idiomatic one in Scala, the Try type:

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

scala> try {
     |   throw new java.io.IOException("no such file")
     | } catch {
     |   case ex: java.io.IOException => println(ex)
     | }
java.io.IOException: no such file

scala> Try {
     |   throw new java.io.IOException("no such file")
     | } match {
     |   case Failure(ex) => println(ex)
     |   case Success(value) => println(s"success: ${value}")
     | }
java.io.IOException: no such file

Both approaches are equivalent, but the last one allows us to treat the exception as a value and chain computations in a more functional programming approach.

2.1. Handling Multiple Exceptions With try-catch Blocks

If we have a method returning different exceptions, we need to handle them.  Following a more Java-style solution, we’ll have independent catch clauses for each exception type, even if the treatment is the same:

try {
  throw new IllegalArgumentException("wrong argument")
} catch {
  case ex: IllegalArgumentException => handleParamsExceptions(ex)
  case ex: MalformedParametersException => handleParamsExceptions(ex)
  case ex: NoSuchElementException => handleMissingExceptions(ex)
}

This works if all the exceptions have the same parent class, but if not, we need a different solution:

try {
  throw new IllegalArgumentException("wrong argument")
} catch {
  case IllegalArgumentException | MalformedParametersException => println("got an exception on params")
  case ex: NoSuchElementException => handleMissingExceptions(ex)
}

We grouped several exception types in the same pattern-matching clause. Unfortunately, this doesn’t allow us to access the exception variable itself. For that, we need to bind the whole pattern to a variable:

try {
  throw new IllegalArgumentException("wrong argument")
} catch {
  case ex @ (IllegalArgumentException | MalformedParametersException) => println(s"got an exception on params: $ex")
  case ex: NoSuchElementException => handleMissingExceptions(ex)
}

And now we can group exceptions together.

2.2. Handling Multiple Exceptions With scala.util.Try Container

If we decide to use the Scala Try container instead, the code is very similar:

import scala.util.{Failure, Success, Try}
val tryVal: Try[Int] = Try {myMethod()}
tryVal match {
  case Success(value) => println(s"success: ${value}")
  case Failure(ex) => ex match {
    case ex @ (RuntimeException | NullPointerException) => println(s"got an exception on params: $ex")
    case _ => println("something unexpected happened")
  }
}

def myMethod(): Int = {
  throw new RuntimeException("wrong argument")
}

We just need to pattern match on the Failure value.

3. Conclusion

In this article, we’ve learned how to group different exception types in the same catch clause, both using the Java-style try-catch block and the scala.util.Try container.

Comments are closed on this article!