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