本文介绍了捕获并重新抛出异常,但这不是异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我偶然发现了看起来像这样的代码:

I stumbled upon code looking something like this:

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        System.out.println("Error: " + ex);
        throw ex;
    }
}

void doSomething() {
    throw new RuntimeException();
}

此代码使我感到惊讶,因为它看起来像运行()方法能够引发 Exception ,因为它捕获了 Exception 然后重新抛出它,但是没有声明该方法抛出 Exception ,并且显然不需要。这段代码可以很好地编译(至少在Java 11中)。

This code surprises me because it looks like the run()-method is capable of throwing an Exception, since it catches Exception and then rethrows it, but the method is not declared to throw Exception and apparently doesn't need to be. This code compiles just fine (in Java 11 at least).

我的期望是我将不得不声明 run()方法中抛出异常

My expectation would be that I would have to declare throws Exception in the run()-method.

额外信息

以类似的方式,如果声明 doSomething 抛出 IOException ,则只需在 run()方法中声明 IOException ,甚至尽管 Exception 被捕获并重新抛出。

In a similar way, if doSomething is declared to throw IOException then only IOException needs to be declared in the run()-method, even though Exception is caught and rethrown.

void run() throws IOException {
    try {
        doSomething();
    } catch (Exception ex) {
        System.out.println("Error: " + ex);
        throw ex;
    }
}

void doSomething() throws IOException {
    // ... whatever code you may want ...
}

问题

Java通常喜欢清晰,这种行为背后的原因是什么?一直都是这样吗? Java语言规范中的什么允许 run()方法不需要在上面的代码片段中声明 throws Exception ? (如果我要添加它,IntelliJ会警告我永远不会抛出 Exception )。

Java usually likes clarity, what is the reason behind this behavior? Has it always been like this? What in the Java Language Specification allows the run() method not need to declare throws Exception in the code snippets above? (If I would add it, IntelliJ warns me that Exception is never thrown).

推荐答案

我没有按照您在问题中所要求的方式浏览 JLS ,因此请带一点盐来回答这个问题。我想发表评论,但它太大了。

I have not scan through the JLS as you have asked in your question, so please take this answer with a grain of salt. I wanted to make it a comment, but it would have been too big.

我有时觉得很有趣, code> javac 在某些情况下(例如在您的情况下)相当聪明,但是留下了许多其他事情,稍后由 JIT 。在这种情况下,只是编译器知道只会捕获到 RuntimeException 。这很明显,这是您在 doSomething 中唯一遇到的事情。如果您将代码略微更改为:

I find funny at times, how javac is pretty "smart" in some cases (like in your case), but leaves a lot of other things to be handled later by JIT. In this case, it is just that the compiler "can tell" that only a RuntimeException would be caught. This is obvious, it's the only thing you throw in doSomething. If you slightly change your code to:

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        Exception ex2 = new Exception();
        System.out.println("Error: " + ex);
        throw ex2;
    }
}

您会看到不同的行为,因为现在 javac 可以告诉您正在抛出一个新的 Exception ,与捕获的异常无关。

you will see a different behavior, because now javac can tell that there is a new Exception that you are throwing, un-related to the one you caught.

但是事情远非理想,您可以通过以下方式再次欺骗编译器:

But things are far from ideal, you can "trick" the compiler yet again via:

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        Exception ex2 = new Exception();
        ex2 = ex;
        System.out.println("Error: " + ex);
        throw ex2;
    }
}

IMO,因为 ex2 = ex; 应该不会再次失败,但是会失败。

IMO, because of ex2 = ex; it should not fail again, but it does.

仅在使用 javac 13 + 33

这篇关于捕获并重新抛出异常,但这不是异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-06 22:54