考虑以下界面:
public interface Generator {
String generate() throws IOException;
}
以及以下实施:
public class EmptyStringGenerator implements Generator {
@Override
public String generate() {
return "";
}
}
请注意,我省略了throws IOException
接口中指定的签名的Generator
部分。然而,没有编译器错误,没有编译器警告,甚至没有@Override
注释抱怨。
我知道这是按预期工作的。但是,我想知道这背后的意图。如果我的方法实际上没有抛出IOException
,那么就可以不抛出它,我不必从签名中删除它。但是,如果我从EmptyStringGenerator
中的方法签名中删除它,我强制此类的所有当前和未来的子类放弃抛出实际在接口中指定的异常的可能性。
对我而言,这听起来像是一个并没有给你带来任何好处的功能(除了保存几次击键,这根本不是一个好处),但有可能成为一个可怕的错误,当时实际使用过。
所以我的问题是,有效的是:在派生类中省略throws
异常有什么意义?这种可能性解决了什么问题?为什么允许这样做?
更新
对于那些问“但那里有什么危害?”的人来说,这是我的一个评论的例子。顺便说一下,这并不是牵强附会,因为这正是我现在正在处理的事情:
程序员A指定接口I.程序员B编写实现类X,但忘记添加抛出。他也没有注意到,因为这里甚至没有警告。程序员C编写实现类Y,继承自X类,他甚至还特意想把投掷放在那里,因为他会扔掉。但即使界面规定了这一点,由于B的疏忽,他现在不再允许这样做了。实际上他不再允许在这里使用该例外。这是一个非常大的伤害。特别是如果X级不在你的控制之下。
答案 0 :(得分:1)
如果省略派生类中的throws
异常,则可以调用派生类的方法,而不必捕获异常。
确保EmptyStringGenerator
的子类也不会抛出异常。否则,对于编译器,如果方法调用可能导致代码必须处理的已检查异常,则无法确定。在这种情况下,throws
根本没有意义。
答案 1 :(得分:0)
根据你的课程变化,考虑这两个条件:
EmptyStringGenerator generator = new EmptyStringGenerator();
generator.generate();
如果像上面那样创建一个EmptyStringGenerator实例,由于省略了EmptyStringGenerator中的throws,上面的代码表明你正在使用类本身,这当然与接口无关,所以代码工作得很好。
但如果您打算使用界面而不是类,请执行以下操作:
Generator generator = new EmptyStringGenerator();
generator.generate();
比编译器实际上会提醒您存在未处理的异常,您必须使用try-catch处理它或抛出它,否则代码将无法编译。
如果以后一种方式使用EmptyStringGenerator的任何子类,则会发生相同的编译错误。所以省略throw实际上并没有让你处理异常。当没有要抛出时,很自然不会在类及其子类中抛出异常,但是当您通过接口调用该方法时,仍然必须处理该异常。
答案 2 :(得分:0)
在Java中,可以正常使用,在实现或扩展时,可以减少类的限制,这是Java开发人员的设计决策。我不能说为什么Sun以这种方式决定它,当然我可以理解你的问题,但目前的方式也有一些好处。
我认为接口可以为一个作业提供多个实现。例如,List类具有针对不同需求的不同实现。但它们都可以通过List界面使用。让我们说如果元素不是列表的一部分,remove方法抛出CheckedException。现在,如果我的实现不能减少限制,所有List类必须抛出此CheckedException,即使它们不需要或不使用它。
因此,如果我在我的类内部使用remove方法,我将被迫处理CheckedException。如果我在没有接口的情况下直接使用我的List类,我将被迫捕获异常。但对于这两种情况,我很确定我不需要它,它永远不会发生。因此,使用当前的方法,我可以节省大量“try catch ignore”块。
当前解决方案的另一个好处是类可以轻松匹配类似的接口。
所以例如在一个lib中有人添加了一个:
public interface Generator {
String generate() throws IOException;
}
在另一个lib中:
public interface GeneratorInterface {
String generate();
}
如果我用没有任何CheckedException的generate方法编写一个类,我可以很容易地使用它来满足这两个接口,也许可以同时使用这两个库:
public class EmptyStringGenerator implements Generator,GeneratorInterface {
@Override
public String generate() {
return "";
}
}
另据我所知,Java是唯一一种处理Checked和Unchecked异常的语言,因此与没有Checked异常的其他语言相比,通过Java的设计决策很奇怪。