This is an excerpt from the 1st Edition of the Scala Cookbook (partially modified for the internet). This is Recipe 5.8, “How to declare that a Scala method can throw an exception.”
Problem
You want to declare that a Scala method can throw an exception, either to alert callers to this fact or because your method will be called from Java code.
Solution
Use the @throws
annotation to declare the exception(s) that can be thrown. To declare that one exception can be thrown, place the annotation just before the method signature:
@throws(classOf[Exception]) override def play { // exception throwing code here ... }
To indicate that a Scala method can throw multiple exceptions, list them all before the method signature:
@throws(classOf[IOException]) @throws(classOf[LineUnavailableException]) @throws(classOf[UnsupportedAudioFileException]) def playSoundFileWithJavaAudio { // exception throwing code here ... }
Discussion
The two examples shown are from an open source project I created that lets developers play WAV, AIFF, MP3, and other types of sound files. I declared that these two methods can throw exceptions for two reasons. First, whether the consumers are using Scala or Java, if they’re writing robust code, they’ll want to know that something failed. Second, if they’re using Java, the @throws
annotation is the Scala way of providing the throws
method signature to Java consumers.
The example I showed is equivalent to declaring that a Java method throws an exception with this syntax:
public void play() throws FooException { // code here ... }
It’s important to note that Scala’s philosophy regarding checked exceptions is different than Java’s. Scala doesn’t require that methods declare that exceptions can be thrown, and it also doesn’t require calling methods to catch them. This is easily demonstrated in the REPL:
// 1) it's not necessary to state that a method throws an exception scala> def boom { | throw new Exception | } boom: Unit // 2) it's not necessary to wrap 'boom' in a try/catch block, but ... scala> boom java.lang.Exception at .boom(<console>:8) // much more exception output here ...
Although Scala doesn’t require that exceptions are checked, if you fail to test for them, they’ll blow up your code just like they do in Java. In the following example, the second println
statement is never reached because the boom method throws its exception:
object BoomTest extends App { def boom { throw new Exception } println("Before boom") boom // this line is never reached println("After boom") }
Java Exception Types
As a quick review, Java has (a) checked exceptions, (b) descendants of Error
, and (c) descendants of RuntimeException
. Like checked exceptions, Error
and RuntimeException
have many subclasses, such as RuntimeException
’s famous offspring, NullPointerException
.
According to the Java documentation for the Exception
class, “The class Exception
and any subclasses that are not also subclasses of RuntimeException
are checked exceptions. Checked exceptions need to be declared in a method or constructor’s throws clause if they can be thrown by the execution of the method or constructor and propagate outside the method or constructor boundary.”
The following links provide more information on Java exceptions and exception handling:
- The Three Kinds of (Java) Exceptions
- Unchecked Exceptions — The Controversy
- Wikipedia discussion of checked exceptions
- Java tutorial on exception handling
- Java Exception class
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |
See Also
- Recipe 17.2, “Add Exception Annotations to Scala Methods to Work with Java”, for other examples of adding exception annotations to methods