7

考虑以下接口:

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,但忘记添加 throws。他也从来没有注意到,因为这里甚至没有发出警告。程序员 C 写了实现类 Y,继承自类 X,他甚至特意也想把 throws 放在那里,因为他要扔了。但即使界面有规定,现在也不允许他再这样做了,因为B的疏忽。他实际上不再被允许在这里使用该例外。这是一个相当大的伤害。特别是如果 X 类不在您的控制之下。

4

3 回答 3

1

If you omit the throws exception in derived classes you can call the method of the derived class without having to catch the exception.

You make sure that subclasses of EmptyStringGenerator also don't throw an exception. Otherwise it would not be sure for the compiler if the method call can cause a checked exception which the code must handle. In that case the throws wouldn't make sense at all.

于 2013-09-11T11:58:01.257 回答
0

根据您的班级声明,有以下两个条件:

    EmptyStringGenerator generator = new EmptyStringGenerator();
    generator.generate();

如果你像上面一样创建一个 EmptyStringGenerator 的实例,由于你省略了 EmptyStringGenerator 中的 throws,上面的代码表明你正在使用类本身,这当然与接口无关,所以代码可以正常工作。

但是如果你打算使用接口而不是类,像这样:

    Generator generator = new EmptyStringGenerator();
    generator.generate();

编译器实际上会提醒您有一个未处理的异常,您必须使用 try-catch 处理它或抛出它,否则代码将无法编译。

如果您以后一种方式使用 EmptyStringGenerator 的任何子类,则会出现相同的编译错误。因此,省略 throw 实际上并不会让您从处理异常中解脱出来。一个类及其子类在没有可抛出异常的情况下不抛出异常是很自然的,但是当您通过接口调用方法时,仍然必须处理异常。

于 2013-09-11T12:47:36.427 回答
0

在 Java 中,您可以在实现或扩展时减少对类的限制,这是 Java 开发人员的设计决定。我不能说为什么 Sun 会这样决定,当然我可以理解你的问题,但目前的方式也有一些好处。

我认为一个接口可以为一项工作提供多种实现。例如,针对不同需求具有不同实现的 List 类。但它们都可以通过 List 接口使用。假设如果元素不是列表的一部分,则 remove 方法会引发 CheckedException。现在,如果在我的实现中不能减少限制,所有 List 类都必须抛出这个 CheckedException,即使它们不需要或使用它。

因此,如果我在我的类内部使用 remove 方法,我将被迫处理 CheckedException。如果我在没有接口的情况下直接使用我的 List 类,我将被迫捕获异常。但对于这两种情况,我很确定我不需要它,它永远不会发生。因此,使用当前方法,我可以节省很多“try catch ignore”块。

当前解决方案的另一个好处是类可以轻松匹配类似的接口。

因此,例如在一个库中,有人添加了一个:

public interface Generator {
    String generate() throws IOException;
}

在另一个库中:

public interface GeneratorInterface {
    String generate();
}

如果我用 generate 方法编写一个没有任何 CheckedException 的类,我可以轻松地使用它来满足两个接口,并且可以使用两个库:

public class EmptyStringGenerator implements Generator,GeneratorInterface {

    @Override
    public String generate() {
        return "";
    }
}

此外,据我所知,Java 是唯一一种可以处理 Checked 和 Unchecked 异常的语言,因此与其他没有 Checked 异常的语言相比,通过 Java 进行的设计决策很奇怪。

于 2013-09-11T15:31:21.693 回答