80

How to catch multiple exceptions at once in Scala? Is there a better way than in C#: Catch multiple exceptions at once?

1
  • For me it turned out I wanted to show both exceptions, one caused by the other, which I solved with the method .initCause. Commented Feb 25, 2023 at 5:08

5 Answers 5

175

You can bind the whole pattern to a variable like this:

try {
   throw new java.io.IOException("no such file")
} catch {
   // prints out "java.io.IOException: no such file"
   case e @ (_ : RuntimeException | _ : java.io.IOException) => println(e)
}

See the Scala Language Specification page 118 paragraph 8.1.11 called Pattern alternatives.

Watch Pattern Matching Unleashed for a deeper dive into pattern matching in Scala.

Sign up to request clarification or add additional context in comments.

2 Comments

which does not pass trough the sbt clean coverage test coverageReport at the time of writing ... github.com/scoverage/sbt-scoverage/issues/257
Not sure why this _: is required before every exception class name, looks to me no use
34

As you have access to the full pattern matching capabilities of scala in the catch clause, you can do a lot :

try {
  throw new IOException("no such file")
} catch {
  case _ : SQLException | _ : IOException => println("Resource failure")
  case e => println("Other failure");
}

Note that if you need to write the same handlers time and time again you can create your own control structure for that :

def onFilesAndDb(code: => Unit) { 
  try { 
    code 
  } catch {
    your handling code 
  }
}

Some such methods are available in object scala.util.control.Exceptions. failing, failAsValue, handling may be just what you need

Edit : Contrary to what is said below, alternative patterns can be bound, so the proposed solution is needlessly complex. See @agilesteel solution

Unfortunately, with this solution, you have no access to the exception where you use the alternative patterns. To my knowledge, you cannot bind on an alternative pattern with case e @ (_ : SqlException | _ : IOException). So if you need access to the exception, you have to nest matchers :

try {
  throw new RuntimeException("be careful")
} catch  {
  case e : RuntimeException => e match {
    case _ : NullPointerException | _ : IllegalArgumentException => 
      println("Basic exception " + e)
    case a: IndexOutOfBoundsException => 
      println("Arrray access " + a)
    case _ => println("Less common exception " + e)
  }
  case _ => println("Not a runtime exception")
}

3 Comments

Interesting, I haven't seen pattern alternatives before. I think they're not covered in PinS.
Binding a pattern alternative works, and is especially useful in this case. The bound variable even gets as type the most specific common supertypes of the alternatives. Nesting marchers is unnecessary. I'll upvote your answer if you update it saying so.
@Jean-Philippe : Excellent!! I tried before answering and could not make that work. Checking the spec probably too quickly, I thought it said the same (on page 113 alternative is Pattern and you can bind only on Pattern3). What is the syntax?
16

You can also use scala.util.control.Exception:

import scala.util.control.Exception._
import java.io.IOException

handling(classOf[RuntimeException], classOf[IOException]) by println apply { 
  throw new IOException("foo") 
}

This specific example might not be the best example to illustrate how you can use it, but I find it pretty useful in many occasions.

Comments

2

Scala version 3 (released in 2021) supports union types, which creates another solution to the already mentioned solutions, although it looks very very similar, but it's different:

(For comparison, I've used the code from solution https://stackoverflow.com/a/6385333/1039774 from 2011, and changed it to Scala 3 with union types, and the new operator can be omitted in Scala 3.)

try {
   throw IOException("no such file")
} catch {
   // prints out "java.io.IOException: no such file"
   case e: (RuntimeException | IOException) => println(e)
}

Comments

0

This was the only way for me, which passed trough the sbt clean coverage test coverageReport without throwing the nasty parsing exception ...

try {
   throw new CustomValidationException1( 
      CustomErrorCodeEnum.STUDIP_FAIL,
      "could be throw new CustomValidationException2")
    } catch {
    case e
      if (e.isInstanceOf[CustomValidationException1] || e
      .isInstanceOf[CustomValidationException2]) => {
        // run a common handling for the both custom exceptions
        println(e.getMessage)
        println(e.errorCode.toString) // an example of common behaviour 
    }
    case e: Exception => {
      println("Unknown error occurred while reading files!!!")
      println(e.getMessage)
      // obs not errorCode available ...
    }
}

    // ... 
    class CustomValidationException1(val errorCode: CustomErrorCodeEnum, val message: String)
    class CustomValidationException2(val errorCode: CustomErrorCodeEnum, val message: String)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.