为什么需要捕获“Exception”而不是子类“RuntimeException”?

时间:2016-05-11 18:23:53

标签: java exception exception-handling

下图显示“Checked”和“Unchecked”异常是Exception的子类。我发现你需要抓住Exception但你不需要抓住RuntimeException直接继承Exception,这让我感到困惑。有没有理由让开发人员不让我们抛出异常而不需要抓住它们?

更具体地说:为什么你只能忽略RuntimeExceptions和它的孩子?为什么没有一个被称为CheckedException extends Exception的类被引入而你只需要捕获它并且它是孩子?

令人困惑的部分是,您可以毫无问题地将所有内容丢弃到RuntimeException以下,但是当您在层次结构中向上移动到Exception时,您需要在某个时刻捕获它。这很令人困惑,因为“抽象”通常会起作用。你向上移动的越多,所有东西都越简单,越多。这不是这种情况。你移动得越多,你就越需要做(比如,在达到Exception后放置try / catch)。

enter image description here

5 个答案:

答案 0 :(得分:5)

如果取消选中Exception,那么您可以隐式地将已检查的异常强制转换为未经检查的异常,这意味着您可以抛出已检查的异常,而不会像以下那样捕获它们:

public void f() {
    Exception e = new IOException();
    throw e;
}

并且使用重写方法,如果抛出更具体的异常,可以添加需求以捕获超类中不存在的异常:

public void f() throws Exception {
}

...

@Override
public void f() throws IOException {
}

答案 1 :(得分:4)

假设他们以另一种方式设计它。我们有一个CheckedException类,需要处理它的子类,而不是Exception的其他子类。

现在我们调用一个可能抛出任意Exception的方法:

public static void example() {
    functionThatThrowsException();
}

我们需要处理吗? ,因为Exception可能是CheckedException。如果我们不需要处理它,我们就会绕过已检查异常的检查性质。

必须将带有已检查后代的throwable类型视为已检查,因此检查自然会在继承层次结构中向上传播。相反,未经检查的throwable类型无法检查后代,因此未检查自然会向下传播。这样就可以自然地将checkness作为默认值,并将特定类及其后代单独列为未选中。

答案 2 :(得分:1)

CheckedException(确实存在)和RuntimeException都延伸Exception。因此,如果有东西抛出一个通用的Exception(这总是一个坏主意),就无法判断异常是否是一个或另一个,所以你必须抓住它以防万一#39}检查一个。如果您以这种方式考虑层次结构,那么实际上 会越走越简单。

您似乎认为已检查的例外更多"复杂"因为你必须做更多的事情来解决它们。这对于思考它来说并不是一种太健康的方式。相反,请考虑这一点:例外是程序本身的问题 - 代码。我们需要找到这些异常并正确处理它们。在已经有了这种异常处理概念之后,我们发现存在一些我们无法预测的问题。

"我怎么知道用户会输入“喵喵”。当被问到整数时!我不应该围绕它编码!"因此,NumberFormatException诞生了,你不必抓住它,因为它是一个逻辑错误"而不是由坏代码引起的问题(虽然,可以说,如果你不以某种方式处理这种情况,可能会被认为是错误的代码。)

简而言之,改变你的想法。 Exception可以处理的程序问题。然而,有一些例外是意外,并且是设计不良而不是错误代码的结果。因此,RuntimeException添加不可能出现,但肯定会发生。

答案 3 :(得分:1)

也许在继承方面不考虑异常类,而只是简单地分离类的集合,一组被检查而另一组则没有。你是对的,可能有一个CheckedException类,只允许我们在明确预定时进行检查。

但是,检查更宽/广义范围有助于强制执行catch or specify模式。检查异常后,代码的读者可以快速找出这段代码需要特别注意并在编译时强制执行它们的处理,从而减少运行时错误。

我们可以抛出任何类型的异常,选中或取消选中。如果要将Exception或任何超级RuntimeException设置为已检查的异常,则所有子类都将成为已检查的异常。由于编译器很可能检查throws子句中的异常实例或类是否派生自类。它可以很容易地通过检查一个特定的包来完成,这个包可能更合适,因为被检查或取消选中与继承无关。

答案 4 :(得分:1)

您的图片已包含答案 - Throwable已被选中且必须被捕获,因为Exception被检查等等,除了RuntimeException及其后代之外。

已检查异常必须被捕获或重新抛出(JLS §11.2)。这是由java编译器保证,因此我们确保将处理我们的“异常”情况。

  

此编译时检查是否存在异常处理程序   旨在减少不正确的例外情况   处理。

如果反转逻辑,则无法在编译时提供这些保证:

public void notReallySafeMethod() {
    try {
        connect();
    } catch (IOException io) {
        Exception e = io;
        throw e; // IOException is unhandled
    }
}

public void suspiciousMethod() throws Exception {};

public void callSuspicious() {
    suspiciousMethod(); // what real type would be thrown? we can't know
    //  should I try-catch everything then?
}