In Java you can't specify that an overridden abstract method throws
some exception if the original abstract method does not (overridden method does not throw Exception
.) However in Scala you can do this since it doesn't have checked exceptions. Fine, but if you use the @throws
annotation that should tip the Java compiler off to what's going on, right?
Given this Scala code:
package myscala
abstract class SFoo {
def bar(): Unit
}
class SFoobar extends SFoo {
@throws[Exception]
override def bar(): Unit = {
throw new Exception("hi there")
}
}
I have two different Java programs, one of which will compile and run into an Exception
at runtime, and the other which will not compile.
Compiles:
import myscala.SFoo;
import myscala.SFoobar;
public class Foobar {
public static void main(String[] args) {
SFoo mySFoo = new SFoobar();
mySFoo.bar();
}
}
Doesn't compile (unreported exception Exception; must be caught or declared to be thrown
):
import myscala.SFoo;
import myscala.SFoobar;
public class Foobar {
public static void main(String[] args) {
SFoobar mySFoo = new SFoobar(); // only difference is the declared type
mySFoo.bar();
}
}
I don't really get it. Why doesn't the Java compiler pick up on the fact that I'm declaring that SFoobar.bar
throws an exception even though Foo.bar
has no such declaration, and as a result, raise a similar compilation error?
If you convert the Scala code for SFoo
and SFooBar
to equivalent Java code:
abstract class SFoo {
void bar() {}
}
class SFoobar extends SFoo {
void bar() throws Exception {
throw new Exception("hi there");
}
}
It doesn't compile, because:
error: bar() in SFoobar cannot override bar() in SFoo
void bar() throws Exception {
^
overridden method does not throw Exception
Java enforces the rule that overriding methods cannot throw exceptions that weren't thrown by the method they are overriding. This makes checked exceptions typesafe when upcasting, e.g. when converting a SFooBar
to an SFoo
.
Your first definition of the FooBar
class, where an SFooBar
is stored in a SFoo
variable, would be perfectly safe if SFoo
and SFooBar
had been defined in Java. The Java compiler knows that an SFoo.bar
doesn't throw Exception
, assumes that the rule for overridden methods was observed, and so doesn't do any extra checks here.
However, the Scala compiler doesn't care about this rule for overridden methods, and will allow you to break this type safety. The Java compiler is oblivious to this fact, and so produces code that breaks at runtime. It's a mismatch between Java and Scala that neither compiler can work around.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With