How to add exception annotations to Scala methods so they can be called from Java

This is an excerpt from the 1st Edition of the Scala Cookbook (partially modified for the internet). This is a short recipe, Recipe 17.2, “How to add exception annotations to Scala methods so they can be called from Java.”

Problem

You want to let Java users know that a Scala method can throw one or more exceptions so they can handle those exceptions with try/catch blocks.

Solution

Add the @throws annotation to your Scala methods so Java consumers will know which methods can throw exceptions and what exceptions they throw.

For example, the following Scala code shows how to add an @throws annotation to let callers know that the exceptionThrower method can throw an Exception:

// scala
class Thrower {
    @throws(classOf[Exception])
    def exceptionThrower {
        throw new Exception("Exception!")
    }
}

With your Scala method annotated like that, it will work just like a Java method that throws an exception. If you attempt to call exceptionThrower from a Java class without wrapping it in a try/catch block, or declaring that your Java method throws an exception, the compiler (or your IDE) will give you the following error:

unreported exception java.lang.Exception; must be caught or declared to be thrown

In your Java code, you’ll write a try/catch block as usual to handle the exception:

// java
Thrower t = new Thrower();
try {
    t.exceptionThrower();
} catch (Exception e) {
    System.err.println("Caught the exception.");
    e.printStackTrace();
}

If you want to declare that your Scala method throws multiple exceptions, add an annotation for each exception:

@throws(classOf[IOException])
@throws(classOf[LineUnavailableException])
@throws(classOf[UnsupportedAudioFileException])
def playSoundFileWithJavaAudio {
    // exception throwing code here ...
}

Discussion

If you don’t mark the Scala exceptionThrower method with the @throws annotation, a Java developer can call it without using a try/catch block in her method, or declaring that her method throws an exception. For example, you can define the Scala method as follows, without declaring that it throws an exception:

//scala
def exceptionThrower {
    throw new Exception("Exception!")
}

This method can then be called from Java:

// java
public static void main(String[] args) {
    Thrower t = new Thrower();
    t.exceptionThrower();
}

However, when the Java developer calls exceptionThrower, the uncaught exception will cause the Java method to fail:

[error] (run-main) java.lang.Exception: Exception!
java.lang.Exception: Exception!
     at Thrower.exceptionThrower(Thrower.scala:6)
     at Main.main(Main.java:9)

As shown, if a Java consumer doesn’t know an exception can be thrown, it can wreak havoc on her application.