TL;博士
编译器认为这FileNotFoundException()
可能不是唯一Exception
抛出的。
解释
JLS§11.2.3 异常检查
如果 catch 子句可以捕获(第 11.2 节)已检查的异常类 E1,并且对应于该 catch 子句的 try 块可以抛出已检查的异常类 E2、E1 的子类和前面的 catch 子句,则鼓励 Java 编译器发出警告立即封闭的 try 语句可以捕获已检查的异常类 E3,其中 E2 <: E3 <: E1。
这意味着如果编译器认为你的 catch 块可能抛出的唯一异常是 a FileNotFoundException()
,它会警告你关于你的第二个 catch 块。这不是这里的情况。
但是,下面的代码
try{
throw new FileNotFoundException();
} catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e){ // The compiler warns that all the Exceptions possibly
// catched by IOException are already catched even though
// an IOException is not necessarily a FNFException
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
发生这种情况是因为编译器评估 try 块以确定哪些异常有可能被抛出。
由于编译器不会警告我们Èxception e
,它认为可能会抛出其他异常(例如 RunTimeException)。由于处理这些 RunTimeExceptions 不是编译器的工作,它让它溜走。
其余的答案很有趣,可以理解异常捕获背后的机制。
架构
如您所见,Exception
它在层次结构中处于较高位置,因此必须在IOException
层次结构中处于较低位置之后才声明它。
例子
想象一下有一个IOException
抛出。由于它继承自Exception
,我们可以说 IOException IS-A Exception ,因此它总是会在Exception
块中被捕获,并且IOException
块将无法访问。
现实生活中的例子
比方说,你在一家商店,必须选择裤子。卖家告诉你,裤子从大到小都要试一试,如果找到可以穿的(即使不是你的尺码)你一定要拿下。
你会发现自己买的裤子对你的尺码来说太大了,而且你没有机会找到适合你的裤子。
你去另一家商店:在那里,你发生了完全相反的事情。你可以从最小到最大选择你的裤子,如果你找到一条你可以穿的,你必须把它拿走。
您会发现自己购买的裤子与您的尺码完全一致。
这有点类比,有点奇怪,但它不言自明。
从 Java 7 开始,您可以选择将 try 块可能抛出的所有异常类型包含在一个且仅 catch 块中。
警告:您还必须尊重层次结构,但这次是从左到右。
在你的情况下,这将是
try{
//doStuff
}catch(IOException | Exception e){
e.printStackTrace();
}
以下示例在 Java SE 7 及更高版本中有效,消除了重复代码:
catch (IOException|SQLException ex) {
logger.log(ex);
throw ex;
}
catch 子句指定块可以处理的异常类型,每种异常类型用竖线 (|) 分隔。