Java无法访问的捕获块编译器错误
为什么在Java中,我们可以捕获一个Java无法访问的捕获块编译器错误,java,scjp,Java,Scjp,为什么在Java中,我们可以捕获一个异常,即使它没有被抛出,但我们不能捕获它的子类(除了“unchecked”RuntimeExceptions和it子类)。示例代码: class Test { public static void main(String[] args) { try { // do nothing } catch (Exception e) { // OK
异常
,即使它没有被抛出,但我们不能捕获它的子类(除了“unchecked”RuntimeException
s和it子类)。示例代码:
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
}
}
}
有什么想法吗?简单地说,Java假设任何代码行都可以抛出一个通用的
异常
或可抛出的异常
,即outofmemory异常
,这是一个错误
,而不是异常
。这同样适用于NPE
IOException
是一种只能由托管代码引发的特定异常,因此如果catch块中没有I/O调用,编译器就没有机会捕捉它
与C#world相比,在C#world中,这样的代码将被编译,但这将是一个概念上的错误,因为如果你不做任何事情,你就不会到达catch块。诸如ReSharper之类的工具可以警告您这一点。任何代码都可能引发
运行时异常。换句话说,编译器无法轻松预测什么样的代码可以抛出它。catch(异常e)
块可以捕获RuntimeException
然而,IOException
是一个选中的异常-只有声明抛出它的方法调用才能这样做。编译器可以(合理地)确信它不可能发生,除非有声明抛出它的方法调用
java编译器根本不考虑“在尝试块中没有任何代码”的情况,它总是允许你捕捉未检查的异常,如在所有合理的情况下,会有可能引发未检查异常的代码。
来自JLS的:
当以下两项均为真时,可到达捕捉块C:
- try块中的某些表达式或throw语句是可访问的,并且可以引发类型可分配给catch子句C的参数的异常。(如果包含表达式的最内层语句是可访问的,则认为该表达式是可访问的。)
- try语句中没有较早的catch块A,因此C的参数类型与A的参数类型相同或是A的参数类型的子类
可以说,编译器应该意识到,在第一种情况下,try块中没有表达式。。。在我看来,这仍然是一个不可触及的条款
编辑:如注释中所述,包含以下内容:
如果catch
子句捕获了选中的异常类型E1,但不存在选中的异常类型E2,则这是一个编译时错误,因此以下所有情况均成立:
- E2因为对于已检查的异常,抛出它们的方法必须通过'throws'关键字显式声明这一事实,因此,如果一个块在您的情况下没有'throws IOException',编译器就有信息表明IOException不可能被抛出,因此无论您在捕获后做什么,它将是不可访问的。您无法捕获未经检查的异常,因为它们无法被抛出。您可以捕获
异常
,因为未经检查的运行时异常是异常
,可能会引发该异常。IOException
是仅由IO相关代码引发的已检查异常。由于try块不执行任何操作,因此不会发生任何与IO相关的操作,也不会抛出IOExceptions,因此不可能执行catch块,编译器也不会让您处理它。
正如您所说,异常可能指的是随时可能发生的未经检查的运行时异常。这就是未检查异常和已检查异常之间的主要区别,这就是为什么编译器不强制执行代码来捕获所有可能的运行时异常。IO异常只能在编译器预测代码中可能存在引发IOException的内容时被捕获。因此,您将收到一条警告,即决不会从try语句体抛出IO异常(因为try语句体中没有任何内容)。如果我们从上面每个人的评论中总结,可以得出结论,像IOException及其子类这样的完全检查的异常意味着要由编译器严格检查,并由相关catch子句抛出。但对于RuntimeException和Exception或Throwable(两者都是部分检查的异常,因为它们都有RuntimeException作为子/孙辈),编译器不能在编译时声明并允许它通过
所以
但是
这意味着没有什么可捕捉的(没有错误)我看不出问题您应该阅读Java语言规范,或者至少是一本好的Java教程。区别在于IOException
(及其所有子类型)都是检查异常,因此编译器可以准确地找出哪些语句可以抛出它们Exception
包括RuntimeException
,因此可能发生在任何语句中(因为它们未经检查且无需声明)。我认为解决方案是这样的,它明确表示Exception
从“必须抛出”检查中排除:“[…]除非E1
是类Exception
”@Joachim:找到了。我会在答案中加上这个。
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){
}