Recently I was playing around with some simple Java code using main
methods to quickly test the code I wrote. I ended up in a situation where I had two classes similar to those:
public class A {
public static void main(String[] args) {
// code here
}
}
public class B extends A {
public static void main(String[] args) throws IOException {
// code here
}
}
I was quite surprised that the code stopped compiling and Eclipse complained that Exception IOException is not compatible with throws clause in A.main(String[])
.
Well, both methods are static and the main
function in B
is just hiding the one from A
, so I thought that there is completely no relation between them. In static methods we have no polymorphism and the call is bound to the concrete method implementation during the compilation, therefore I cannot understand why main
in B
cannot throw exception that is not declared in main
signature in A
.
Why Java designers decided to enforce a constraint like this and in what situations it would cause problems if the constraint was not enforced by the compiler?
For what it's worth, here is the relevant portion of the JLS that enforces this rule.
First, §8.4.8.2. Hiding (by Class Methods) gives a definition for method hiding that applies here:
If a class C declares or inherits a
static
methodm
, thenm
is said to hide any methodm'
, where the signature ofm
is a subsignature (§8.4.2) of the signature ofm'
, in the superclasses and superinterfaces of C that would otherwise be accessible to code in C.
Then, §8.4.8.3. Requirements in Overriding and Hiding states that:
A method that overrides or hides another method, including methods that implement
abstract
methods defined in interfaces, may not be declared to throw more checked exceptions than the overridden or hidden method.More precisely, suppose that B is a class or interface, and A is a superclass or superinterface of B, and a method declaration
m2
in B overrides or hides a method declarationm1
in A. Then:
If
m2
has athrows
clause that mentions any checked exception types, thenm1
must have athrows
clause, or a compile-time error occurs.For every checked exception type listed in the
throws
clause ofm2
, that same exception class or one of its supertypes must occur in the erasure (§4.6) of thethrows
clause ofm1
; otherwise, a compile-time error occurs.
In other words, the error message is not some oversight in the compiler, or a misinterpretation of the spec; the JLS makes the specific effort to mention that throws
clause conflicts are an error with method hiding (i.e., with static methods). There is equivalent language to this in every version of the JLS back to 1.0.
However, I can't definitively answer your question of why the constraint is present in this case. I can't conceive of any situation in which the constraint is necessary, since the issue of which static method implementation is invoked is always completely resolved at compile-time, unlike for instance methods.
I'd bet a small amount of money that whoever first put that constraint in the langspec was simply being over-cautious, figuring it was safer to prevent something than to allow it and then later discover it causes problems. The Java language design is/was not without its fair share of flawed features (checked exceptions being one of them), and this could credibly be another, but this is just a guess.
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