Reputation: 14039
I have the following classes
public abstract interface X
{
public abstract void f() throws java.io.IOException;
}
public class Y implements X
{
public void f() throws java.io.IOException
{
throw new java.ioIOException("Hello");
}
public static void main(String [] args)
{
X x = new Y();
try
{
x.f();
}
catch (IOException e)
{
System.out.println("Caught");
}
}
}
Now I compile both and get X.class
and Y.class
.
Now I change X to remove the throws
public abstract interface X
{
public abstract void f();
}
Obviously if I recompile both X & Y, Y's compilation will fail
Y.java:4: f() in Y cannot implement f() in X; overridden method does not throw j
ava.io.IOException
However, what I if only recompile X.java & keep my Y.class which was compiled with the older X.java.
What happens in such a case - is it well defined?
Or does it fall under the category of undefined - i.e. anything can happen?
Are there any guarantees at all - i.e. if I am running it always under Java 1.6.32 under Windows, can I rely on nothing bad happening?
Update: Updated it because some answers said I would get a IncompatibleClassChangeError
at runtime. But I don't.
Steps
1) Compile both X.java and Y.java as given above. Run Y.
Output: Caught
2) Change X.java to comment out the throws. Recompile X.java. Do not recompile Y.java.
Run Y
Output: Caught
I am running java on Windows 7
Compiler
javac 1.6.0_35
Runtime
java version "1.6.0_35"
Java(TM) SE Runtime Environment (build 1.6.0_35-b10)
Java HotSpot(TM) Client VM (build 20.10-b01, mixed mode, sharing)
Upvotes: 7
Views: 1660
Reputation: 17309
This is a limitation in Java right now. Create a sub-interface that extends your current interface and override the method without the exception if you really need it. Generally speaking, this is called a "binary change" and results in broken linking when the code runs, and is well-defined in the JLS (there's an entire chapter on it, JLS 13, you specifically want JLS 13.5).
Edit: after further investigation, it turns out I was wrong. From JLS 13.4.21:
Changes to the
throws
clause of methods or constructors do not break compatibility with pre-existing binaries; these clauses are checked only at compile time.
However, I'd still recommend not doing this since it means a checked exception can essentially become unchecked at runtime.
Upvotes: 4