如果我使用多个catch块,为什么java没有检测到不可到达的catch块?

如果我使用多个catch块,为什么java没有检测到不可到达的catch块?,java,exception,try-catch,unreachable-code,Java,Exception,Try Catch,Unreachable Code,研究方法如下: static private void foo() { try { throw new FileNotFoundException(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace();

研究方法如下:

static private void foo()  {
        try {
            throw new FileNotFoundException();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
尽管最后一个catch块实际上不可访问,但这段代码编译得很好

现在让comment
抛出新的FileNotFoundException()

执行:

哎呀!我们看到

Unreachable catch block for FileNotFoundException. This exception is never thrown from the try statement body
奇怪。为什么java在这些情况下使用双重标准

@Peter Rader的更新 与构造函数调用一起工作

更新 我注意到,在不同版本的java编译器上,我看到编译这段代码的不同结果

public class RethowTest {

        public static void main(String[] args)  {
            try {
                throw new FileNotFoundException();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                throw e;
            }
        }    
}
在我的本地pc上: 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
(JavaC1.7.0_09)-


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

参见本文:在示例中


如果编译器每次都检查构造函数
FileNotFoundException()
:这是java忽略性能的开销。

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

当以下两项均为真时,可到达捕捉块C:

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

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

  • try语句中没有较早的catch块A,因此C的参数类型与A的参数类型相同或是A的参数类型的子类

请注意,这些规则并不禁止您的示例代码。第二个catch块不符合第二个要点的条件

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

这是不一致的吗?以你为例,你可以说是这样的

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

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

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

  • 如果他们现在修改了规范,那将使一小部分有效的和正常工作的Java程序无效。考虑到稳定性是Java的主要卖点之一,这不是一个好主意

另一方面,我想不出一个技术原因来解释为什么他们不能在规范中解决这个“不一致性”


您注意到,一些Java编译器在第2次捕获时会发出警告消息。这没关系。Java编译器可以对(技术上)合法的Java代码发出警告

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

捕获(异常…
块将捕获运行时异常。原则上,它永远不会无法访问

FileNotFoundException
是一个选中的异常。只有当try块中的某个对象抛出它或它的某个子类时,才能访问它的catch块


[在响应请求时]

异常包括运行时异常。原则上,它从来都不是不可访问的。只有当try块中的某个对象抛出FileNotFoundException或其基类时,才能访问它。@EJP真的-谢谢。@EJP看在上帝的份上,您能将其添加为答案吗?@sᴜʀᴇsʜᴀᴛᴛᴀ EJP评论不是答案-这只是观察以改进问题唯一不太令人满意的借口是FileNotFoundException也是一个IOException,而catch似乎只是检查是否抛出了IOException,而不是考虑到它已经被捕获。+1您是对的。现在它很奇怪-毫无疑问。但是f可能是null,一个null指针异常选项将被抛出,没有人知道NullPointerException是否在IOException中。我不理解你的想法。Null指针是RuntimeException。你不应该检查这些异常。1.不要认为类及其继承不会更改!即使编译器也不认为继承会更改!2.
NumberFormatException
是一个错误
RuntimeException
也一样,你真的应该检查这些异常!@PeterRader这从头到尾都是胡说八道。(1)
newfilenotfoundexception()
不会抛出任何类型的
IOException。
(2)
FileNotFoundException
NullPointerException
在两个方向上都不是继承关系。(3)编译器知道每个构造函数和方法抛出什么,而不“查看构造函数”:它在目标代码中。(4)Java检查所有检查的异常:没有“忽略性能”。@EJP 1.编译器只知道当前JRE/JDK版本的objectcode。在本例中,本机方法
fillInStackTrace
抛出一个
IOException
,该异常在
RuntimeException
的构造函数中被调用(FileNotFoundException也使用)使用:.2。我可以使用动态代理从
NullPointerException
以及继承
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
HelloWorld.java:9: warning: unreachable catch clause
        } catch (IOException e) {
          ^
  thrown type FileNotFoundException has already been caught
1 warning