Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 捕获异常并重新引用它,但它';这也不例外_Java_Exception_Throws - Fatal编程技术网

Java 捕获异常并重新引用它,但它';这也不例外

Java 捕获异常并重新引用它,但它';这也不例外,java,exception,throws,Java,Exception,Throws,我偶然发现这样的代码: void run() { try { doSomething(); } catch (Exception ex) { System.out.println("Error: " + ex); throw ex; } } void doSomething() { throw new RuntimeException(); } 这段代码让我吃惊,因为它看起来像run()-方法能够抛出异常,因为它

我偶然发现这样的代码:

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

void doSomething() {
    throw new RuntimeException();
}
这段代码让我吃惊,因为它看起来像
run()
-方法能够抛出
异常
,因为它捕获
异常
,然后重新抛出它,但该方法没有声明抛出
异常
,显然不需要。这段代码编译得很好(至少在Java11中)

我的期望是必须在
run()
-方法中声明
抛出异常

额外信息

以类似的方式,如果
doSomething
被声明为抛出
IOException
,则在
run()
-方法中只需声明
IOException
,即使捕获并重新调用了
Exception

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()
方法不需要在上面的代码片段中声明
抛出异常
?(如果我想添加它,IntelliJ警告我,永远不会抛出
异常)。

我没有像你在问题中所问的那样扫描
JLS
,因此请对这个答案持保留态度。我想对它发表评论,但它太大了


有时候我觉得很有趣,
javac
在某些情况下(比如在您的情况下)是非常“聪明”的,但是将许多其他事情留给以后由
JIT
处理。在这种情况下,只是编译器“能告诉”只有
RuntimeException
会被捕获。这是显而易见的,这是你投入的唯一东西。如果您稍微将代码更改为:

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        Exception ex2 = new Exception();
        System.out.println("Error: " + ex);
        throw ex2;
    }
}
您将看到一个不同的行为,因为现在
javac
可以看出您正在抛出一个新的
异常
,与您捕获的异常无关

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

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        Exception ex2 = new Exception();
        ex2 = ex;
        System.out.println("Error: " + ex);
        throw ex2;
    }
}
IMO,因为
ex2=ex它不应该再次失败,但它确实失败了


以防万一,这是用
javac13+33

编译的。你在用什么编译器?如果是IDE编译器,那么请检查
javac
——我遇到过Eclipse编译器更宽松的情况。我可以在openjdk-8上重现这种行为。值得注意的是,使用
-source 1.6
标志编译时会产生预期的编译错误。使用source compatibility 7进行编译不会引发编译错误似乎编译器是从Java 7开始的,并且会对可能引发的实际异常进行更多检查。这个问题不是重复的,答案可以在Java SE 7及更高版本中我提供的
详细链接中找到,当您在catch子句中声明一个或多个异常类型,并重试此catch块处理的异常时,编译器将验证重试异常的类型是否满足以下条件:1。1.试块可以把它扔出去。2.没有其他前面的catch块可以处理它。3.它是catch子句的异常参数之一的子类型或超类型。
绝对相关,但在IMO中没有提供足够详细的答案。答案的注释中有一个指向JLS的链接,除此之外,没有任何信息。我在一些链接中读到,有人提供,如果您在catch块中重新分配捕获的异常,那么编译器将无法智能化。我认为类似的情况也适用于这种情况。编译器知道将抛出
ex2
异常,它最初创建为
异常
,但随后被重新分配到
ex
,因此编译器不可能聪明。@SimonForsberg对
JLS
有热情的人可能会来提供所需的引用来证明这一点;不幸的是,我没有它们。对于记录,当我更改catch块以包含捕获的异常对自身的重新分配(
ex=ex;
)时,启发式不再应用。这种行为似乎适用于从7到11的所有源级别,可能13请看一看问题,这也是一个重复的问题。这一个和可能的dup的dup解释了它,并链接到JLS。