8

研究以下方法:

static private void foo()  {
        try {
            throw new FileNotFoundException();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

尽管最后一个 catch 块实际上无法访问,但这段代码编译得很好。

现在让我们评论 throw new FileNotFoundException();

执行:

哎呀!我们看

Unreachable catch block for FileNotFoundException. This exception is never thrown from the try statement body

奇怪的。为什么java对这些情况使用双重标准?

@Peter Rader 的更新

static private void foo(FileNotFoundException f)  {
        try {
            throw f;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

与构造函数调用一样工作

更新

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

public class RethowTest {

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

在我的本地电脑上: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

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

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
4

3 回答 3

6

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

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

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

    有关表达式的正常和突然完成,请参见第 15.6 节。

  • try 语句中没有更早的catch 块A,使得C 的参数类型与A 的参数类型相同或子类。

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

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

这是不一致的吗?对于您的示例,您可能会认为是这种情况。

他们为什么不在可达性规则中解决这种情况?我不知道。您需要询问 Java 设计人员!然而:

  • 可达性规则的制定需要更加复杂才能处理这个问题。规范中的额外(不必要的?)复杂性是一个问题。

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

  • 如果他们现在更改规范,那将导致一小部分有效且工作的 Java 程序无效。这不是一个好主意,因为稳定性是 Java 的主要卖点之一。

另一方面,我想不出他们无法解决规范中的这种“不一致”的技术原因


您注意到某些 Java 编译器会在 2 日发出警告消息catch。那没问题。允许 Java 编译器对(技术上)合法的 Java 代码发出警告。

如果它们是错误,那在技术上将是一个编译器错误……根据我对 JLS 的阅读。

于 2014-09-02T22:52:58.847 回答
1

catch (Exception ...)块将捕获运行时异常。原则上它永远是不可触及的。

FileNotFoundException是一个检查异常。仅当 try 块中的某些内容或其子类之一抛出它时,它的 catch 块才可访问。

[应要求]

于 2014-09-02T23:53:36.510 回答
-3

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

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

如果编译器在FileNotFoundException()每次出现时都查看构造函数:它是对性能的开销 java 忽略。

于 2014-09-02T13:28:05.313 回答