4

无参数构造函数抛出一个不可能的异常或有一个空的 catch 块更好吗?假设我有这样的课程。

public class Foo {
    private int num;
    private String numString;

    public Foo() throws NumberFormatException {
        setNum("1");
    }

    public void setNum(String s) throws NumberFormatException {
        // In reality, complex code goes here
        num = Integer.parseInt(s);
        numString = s;
    }
}

编译器强制构造函数要么抛出 NumberFormatException (这永远不会发生),要么有一个 try/catch 块。但是,有一个空的 catch 块是否正确,这通常是不受欢迎的?

public Foo() {
    try {
        setNum("1");
    } 
    catch (NumberFormatException e) { }
}

请注意, Foo 将是一个库类,其他人会使用它,所以让一个无参数构造函数抛出一个不可能的异常会令人困惑。另请注意,真正的异常是自定义异常,而不是 NumberFormatException,这可能会使库用户更加困惑,他们可能会觉得他们必须在不需要时阅读自定义异常。

4

4 回答 4

13

NumberFormatException是 a RuntimeException,所以你不需要在你的throws子句中列出它——只要假装它不存在。这适用于方法和构造函数。

RuntimeException(包括其自身)的任何子类RuntimeException都是“未经检查的异常”,这意味着编译器不会强制您在 try/catch 子句中检查它。相反,任何Exception不是其子类的东西RuntimeException都可以很容易地称为受检异常。

如果它一个已检查异常(即,不是 的子类RuntimeException),但您确定永远无法触发它,那么捕获它是安全的。与其完全吞下它,不如将它包裹在一个未经检查的异常周围。

try {
    thisCodeCanNeverThrowAnIOException();
}
catch (IOException e) {
    throw new AssertionError(e); // juuust in case!
}

现在您的代码可以编译,没有throws针对您从未期望抛出的异常的子句,但是如果由于某些错误或将来的更改,该异常最终确实被抛出,则不会隐藏严重错误。

(阅读评论的人请注意:我最初在代码示例中使用throw new RuntimeException(e),但 Stephen C 和 Peter Lawrey 指出,在 Java 1.4.2 和更新版本中,AssertionError 更好)。

于 2012-05-05T04:32:57.620 回答
1

既然 s 必须是一个数字,为​​什么不通过 setNum() 而不是当前字符串传递一个整数?整数始终可以解析为字符串。

于 2012-05-05T04:29:29.003 回答
1

我想说这取决于您的业务关怀或个人编码风格,如果您选择抛出异常,则拥有和包装的异常可能会更好,如果您传入的参数不正确或没有意义,您可以抛出现在例外。

无论 NumberFormatException 必须抛出什么,这都是你在哪里抓住它的一个公正的决定。它可能在您的库类中,或者在调用者类中,或者在您不知道的地方。没有它,程序将关闭。

在您的情况下,您是否将无编号字符串视为合法值,如果是,则您有责任将异常保留在您的包中。

于 2012-05-05T04:43:02.903 回答
0

我会说:永远不要有一个空的 catch 块(无论如何)。正如@yshavit 指出的那样,吞下可能的错误并不是一个好习惯。

正如@stephen-c 所说,使用断言是向前迈出的一步,但该解决方案有两个缺点:

  1. 也许断言没有在“操作/生产”服务器上启用,所以你真正拥有的非常类似于一个空的 catch 块
  2. 如果它们在服务器上启用,则在执行这段代码期间出现错误将表明您的应用程序中存在错误,只要它是不期望出现的东西(“这不应该发生”,但它发生了!所以...)

所以我的建议是@yshavit 提案。

于 2012-12-04T10:53:44.917 回答