如果我使用多个catch块,为什么java不检测无法访问的catch块?

gst*_*low 8 java exception try-catch unreachable-code

研究方法如下:

static private void foo()  {
        try {
            throw new FileNotFoundException();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
Run Code Online (Sandbox Code Playgroud)

尽管最后一个catch块实际上无法访问,但此代码编译良好.

现在让评论 throw new FileNotFoundException();

执行:

哎呀!我们看

Unreachable catch block for FileNotFoundException. This exception is never thrown from the try statement body
Run Code Online (Sandbox Code Playgroud)

奇怪.为什么java在这些情境中使用双重标准?

更新@Peter Rader

static private void foo(FileNotFoundException f)  {
        try {
            throw f;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
Run Code Online (Sandbox Code Playgroud)

工作以及构造函数调用

更新

我注意到在不同版本的java编译器上,我看到编译此代码的不同结果.

public class RethowTest {

        public static void main(String[] args)  {
            try {
                throw new FileNotFoundException();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                throw e;
            }
        }    
}
Run Code Online (Sandbox Code Playgroud)

在我的本地电脑上:java 1.7.0_45 -

C:\Program Files\Java\jdk1.7.0_45\bin>javac D:\DNN-Project\DNN-Project\src\main\java\exceptionsAndAssertions\RethowTest.java
D:\DNN-Project\DNN-Project\src\main\java\exceptionsAndAssertions\RethowTest.java:15: warning: unreachable catch clause
                } catch (IOException e) {
                  ^
  thrown type FileNotFoundException has already been caught
1 warning
Run Code Online (Sandbox Code Playgroud)

java 1.6.0_38

D:\DNN-Project\DNN-Project\src\main\java\exceptionsAndAssertions\RethowTest.java:16: unreported exception java.io.IOException; must be caught or declared to be thrown
                    throw e;
                    ^
1 error
Run Code Online (Sandbox Code Playgroud)

http://www.compileonline.com/compile_java_online.php(Javac 1.7.0_09) -

HelloWorld.java:9: warning: unreachable catch clause
        } catch (IOException e) {
          ^
  thrown type FileNotFoundException has already been caught
1 warning
Run Code Online (Sandbox Code Playgroud)

Ste*_*n C 6

可访问性规则在Java 8 JLS 14.21(和Java 7)中定义如下:

如果满足以下两个条件,则可以访问catch块C:

  • C参数的类型是未经检查的异常类型或Exception或Exception的超类,或者try块中的某些表达式或throw语句是可到达的,并且可以抛出一个已检查的异常,其类型可分配给C的参数类型.(如果包含它的最内层语句可以访问,则表达式是可到达的.)

    正常和突然完成表达式见§15.6.

  • try语句中没有先前的catch块,因此C的参数类型与A参数类型的子类相同.

请注意,规则不要禁止您的示例代码.第二个捕获块不符合第二个要点的标准.

(在示例的原始版本中,您抓住了Exception.可达性推理会有所不同,但答案是相同的 - 有效代码.)

这是不一致的吗?举个例子,你可以说是这样的.

他们为什么不在可达性规则中解决这个问题呢?我不知道.你需要问Java设计师!! 然而:

  • 为了解决这个问题,可达性规则的制定需要更加复杂.规范中的额外(不必要的?)复杂性是一个问题.

  • 你可以说这种不一致并没有破坏任何东西.可达性规则实际上只是一种在用户代码中发现潜在错误的方法.它不涉及类型安全或可预测的执行; 即会破坏Java运行时语义的东西.

  • 如果他们现在改变了规范,那将使一小部分有效和有效的Java程序无效.鉴于稳定性是Java的主要卖点之一,这不是一个好主意.

在另一方面,我想不出一个技术原因,他们不可能都在规范解决了这个"矛盾".


您注意到某些Java编译器在第二天发出警告消息catch.那没问题.允许Java编译器为(技术上)合法的Java代码提供警告.

如果它们是错误,那在技术上就是编译器错误...根据我对JLS的阅读.

  • @gstackoverflow第二个项目符号意味着您无法捕获`IOException` _followed by_` FileNotFoundException`,因为`FileNotFoundException`是`IOException`的子类.您的示例具有相反的顺序,因此该点不适用. (2认同)

Pet*_*der -3

如果实例化,new FileNotFoundException()则调用 Class 的构造函数FileNotFoundException。在这个构造函数中,理论上可以通过调用本机方法来抛出 IOException fillInStackTrace- 编译器可能不知道构造函数的内容是什么,也许IOException会抛出一个异常。

请参阅这篇文章: https: //community.oracle.com/thread/1445008? start=0 的示例。

FileNotFoundException()如果编译器在每次出现时都会检查构造函数:这会导致 Java 对性能的忽视。

  • 我不明白你的想法。无论如何,空指针是 RuntimeException。您不应该检查这些异常。 (2认同)