Consider the following interface:
public interface Generator {
String generate() throws IOException;
}
and the following implementation:
public class EmptyStringGenerator implements Generator {
@Override
public String generate() {
return "";
}
}
Note that I omitted the throws IOException
part of the signature specified in the Generator
interface. Yet there is no compiler error, no compiler warning, not even the @Override
annotation complains.
I am aware that this is working as intended. I would, however, like to know the intent behind this. If my method does not actually throw an IOException
, it would be fine to just not throw it, I do not have to remove it from the signature. But if I do remove it from my method signature in EmptyStringGenerator
, I am forcing all current and future subclasses of this class to forego the possibility of throwing an exception that is actually specified in the interface.
This, to me, sounds like a feature that does not really bring you any benefit (apart from saving a couple of keystrokes, which is not really a benefit at all), but has the potential to be a terrible mistake, when actually used.
So my question, effectively, is this: What is the point of omitting throws
exceptions in derived classes? What is the problem that this possibility solves? Why is this allowed?
UPDATE
For people asking "but where is the harm in that?", here is my example from one of my comments. It is not far-fetched, by the way, because that is exactly what I am dealing with right now:
Programmer A specifies interface I. Programmer B writes implementation class X, but forgets to add the throws. He also never notices, because there is not even a warning being thrown here. Programmer C writes implementation class Y, inheriting from class X, he even specifically also wants to put the throws there, because he is gonna throw. But even though the interface stipulates it, he is now not allowed to do so anymore, because of B's oversight. He is effectively not allowed to use that exception here anymore. That's a pretty big harm. Especially if class X is not under your control.
In Java its OK and normal that you can make your classes less restrictive when implementing or extending that is a design decision of the Java developer. I can not say why Sun decided it this way and of course I can understand your problem with it, but the current way also has some benefits.
I see an Interface as a possibility to have multiple implementations for one job. For example the List classes which have different implementations for different needs. But they can all be used via the List interface. Lets say the remove method throws a CheckedException if the element is not part of the list. Now if am not able to be less restrictive in my implementations all List classes must throw this CheckedException, even they do not need or use it.
So if I use the remove method internally in my Class I am forced to handle the CheckedException. If I use my List class directly without the Interface I am forced to catch the exception. But for both cases I am pretty sure I do not need it and it will never happen. So with the current approach I can save a lot of "try catch ignore" blocks.
An other benefit of the current solution is that a class can easily match similar Interfaces.
So for example in one lib someone added a:
And in an other lib:
If I write a Class with a generate method without any CheckedException I can easily use this to satisfy both Interfaces and maybe work with both libs:
Also as far as I know Java is the only language with such handling of Checked and Unchecked exceptions and so the design decisions which pull through Java are strange compared with other languages not having Checked exceptions.