java不可访问的catch块编译器错误

amrnrhlw  于 2021-07-09  发布在  Java
关注(0)|答案(7)|浏览(482)

为什么在 java 我们能赶上 Exception 即使它没有被抛出,但是我们不能捕捉它的子类(除了“unchecked”之外) RuntimeException 和它的子类)。示例代码:

class Test {
    public static void main(String[] args) {
        try {
            // do nothing
        } catch (Exception e) {
            // OK           
        }

        try {
            // do nothing
        } catch (IOException e) {
               // COMPILER ERROR: Unreachable catch block for IOException.
               //This exception is never thrown from the try statement body
        }       
    }
}

有什么想法吗?

zkure5ic

zkure5ic1#

因为对于检查过的异常,抛出它们的方法必须通过'throws'关键字显式地声明这个事实,因此,如果一个块在您的情况下没有'throws ioexception',编译器就有信息表明ioexception不可能被抛出,所以无论您在捕获之后做什么,它都是不可到达的。

y3bcpkx1

y3bcpkx12#

如果我们从上面每个人的评论中总结一下,就可以得出这样的结论:像ioexception及其子类这样的完全检查过的异常是由编译器严格检查的,并由相关的catch子句抛出。但是对于runtimeexception和exception或throwable(这两个都是部分检查的exception,因为它们的runtimeexception是子/孙)编译器不能在编译时说并允许它通过。
所以。。

try{
  // Empty - valid
} catch(Exception or Throwable or any Runtime Exception ){

}

但是

try{
  // Empty - invalid and compile time error
} catch (Any fully checked Exception like IOException, FileNotFoundException, EOF/Interruped etc){

}
omqzjyyz

omqzjyyz3#

您不能捕获取消thrown检查的异常,因为它们不能被抛出。你可以抓住 Exception 因为未检查的运行时异常是 Exception 可能会被抛出。

qvsjd97n

qvsjd97n4#

只有当编译器预测代码中可能存在引发ioexception的内容时,才可以捕获io异常。因此,您将收到一个警告:决不会从try语句体抛出io异常(因为try语句体中没有任何内容)。

cnh2zyt3

cnh2zyt35#

IOException 是仅由io相关代码引发的选中异常。因为try块什么都不做,所以不会发生任何与io相关的事情,也不会抛出ioexceptions,所以catch块不可能被执行,编译器也不会让你处理它。正如您所说,异常可能是指在任何时刻都可能发生的未经检查的运行时异常。这就是未检查异常和已检查异常之间的主要区别,这就是为什么编译器不强制执行代码来捕获所有可能的运行时异常。

egdjgwm8

egdjgwm86#

简单地说,java假设任何代码行都可以抛出一个泛型 Exception 或者 Throwable ,即。 OutOfMemoryException 这是一个 Error 相当于 Exception . npe也是如此。 IOException 是一个只能由托管代码引发的特定异常,因此如果catch块中没有i/o调用,编译器就没有机会捕捉它。
与c#world相比,在c#中,这样的代码将被编译,但这将是一个概念上的错误,因为如果不执行任何操作,就不会到达catch块。诸如resharper之类的工具可以警告您这一点。

dzjeubhm

dzjeubhm7#

RuntimeException 可能被任何代码抛出。换句话说,编译器不能很容易地预测什么样的代码可以抛出它。一 RuntimeException 会被一个 catch(Exception e) 阻止。 IOException 但是,是一个选中的异常-只有声明为抛出它的方法调用才能这样做。编译器可以(合理地)确信它不可能发生,除非有声明抛出它的方法调用。
java编译器根本不考虑“try块中根本没有代码”的情况—它总是允许您捕获未检查的异常,因为在所有合理的场景中,都会有可能抛出未检查异常的代码。
根据jls第14.21节:
如果以下两个条件都为真,则可以到达catch块c:
try块中的某个表达式或throw语句是可访问的,并且可以抛出类型可分配给catch子句c的参数的异常(如果包含表达式的最内层语句是可访问的,则认为表达式是可访问的。)
try语句中没有较早的catch块a,因此c的参数类型与a的参数类型相同或是a的参数类型的子类。
可以说,编译器应该意识到,在第一种情况下,try块中没有表达式。。。在我看来,这仍然是一个无法达到的条款。
编辑:如评论所述,第14.20节包含以下内容:
如果 catch 子句捕获选中的异常类型e1,但不存在选中的异常类型e2,因此以下所有类型均有效:
e2<:e1
这个 try 块对应于 catch 子句可以抛出e2
无前导 catch 紧随其后的try语句块捕获e2或e2的超类型。
除非e1是类例外。
所以看起来这就是你实际运行的犯规,但规范并不像14.21中的不可到达的catch块那样清晰。

相关问题