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

时间:2014-09-02 13:14:19

标签: java exception-handling try-catch unreachable-code

研究以下方法:

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

3 个答案:

答案 0 :(得分:6)

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

  

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

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

         

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

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

  •   

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

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

这是不一致的吗?对于你的例子,你可以认为是这种情况。

为什么他们没有在可达性规则中解决这个问题?我不知道。你需要问Java设计师!!但是:

  • 可达性规则的公式需要更加复杂才能解决这个问题。规范中的额外(不必要的)复杂性是一个问题。

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

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

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


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

如果它们是错误,那么从技术上讲,这将是一个编译器错误...根据我对JLS的阅读。

答案 1 :(得分:1)

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

FileNotFoundException是一个经过检查的例外。只有try块中的某些内容或其子类之一才能访问它的catch块。

[回应请求]

答案 2 :(得分:-3)

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

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

如果编译器针对每个资源调查构造函数FileNotFoundException():它是一个忽略性能的开销java。