Javaexception未捕获?

我有一个try-catch结构的小理论问题。

我昨天参加了一个关于Java的实践考试,我不明白下面的例子:

try { try { System.out.print("A"); throw new Exception("1"); } catch (Exception e) { System.out.print("B"); throw new Exception("2"); } finally { System.out.print("C"); throw new Exception("3"); } } catch (Exception e) { System.out.print(e.getMessage()); } 

问题是“产出会是什么样子?”

我非常肯定这将是AB2C3,但惊喜,这是不正确的。

正确的答案是ABC3(testing,真的是这样)。

我的问题是,Exception(“2”)在哪里?

从Java语言规范14.20.2。 :

如果由于原因R catch块突然完成,则执行finally块。 那么有一个select:

  • 如果finally块正常完成,那么由于原因R,try语句突然完成。

  • 如果finally块由于S原因而突然完成,那么try语句因为原因S突然完成(并且原因R被丢弃)

所以,当有一个catch块抛出一个exception时:

 try { // ... } catch (Exception e) { throw new Exception("2"); } 

但是也有一个finally块也会抛出一个exception:

 } finally { throw new Exception("3"); } 

Exception("2")将被丢弃,只有Exception("3")将被传播。

finally块中抛出的exception压缩了try或catch块中之前抛出的exception。

Java 7的例子: http : //ideone.com/0YdeZo

从Javadoc的例子:


 static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException { BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { if (br != null) br.close(); } } 

然而,在这个例子中,如果方法readLine和close都抛出exception,则readFirstLineFromFileWithFinallyBlock方法抛出finally块抛出的exception; 从try块引发的exception被抑制。


Java 7新的try-with语法增加了asynchronous抑制的另一个步骤:try块中抛出的exception抑制了前面在try-part中抛出的exception。

从相同的例子:

 try ( java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName); java.io.BufferedWriter writer = java.nio.file.Files.newBufferedWriter(outputFilePath, charset) ) { for (java.util.Enumeration entries = zf.entries(); entries.hasMoreElements();) { String newLine = System.getProperty("line.separator"); String zipEntryName = ((java.util.zip.ZipEntry)entries.nextElement()).getName() + newLine; writer.write(zipEntryName, 0, zipEntryName.length()); } } 

可以从与try-with-resources语句相关联的代码块中抛出exception。 在上面的例子中,可以从try块抛出一个exception,当试图closuresZipFile和BufferedWriter对象时,最多可以从try-with-resources语句中抛出两个exception。 如果从try块抛出一个exception,并且从try-with-resources语句抛出一个或多个exception,那么从try-with-resources语句抛出的exception就会被取消,而由块抛出的exception是这是由writeToFileZipFileContents方法引发的。 您可以通过从try块引发的exception中调用Throwable.getSuppressed方法来检索这些抑制的exception。


在来自问题的代码中,每个块都明显地丢弃了旧的exception,甚至没有logging它,当你试图解决一些错误时不好:

http://en.wikipedia.org/wiki/Error_hiding

由于throw new Exception("2"); 是从catch块扔出来的,不要try ,不会再被抓到。
见14.20.2。 try-finally和try-catch-finally的执行

这是发生的事情:

 try { try { System.out.print("A"); //Prints A throw new Exception("1"); } catch (Exception e) { System.out.print("B"); //Caught from inner try, prints B throw new Exception("2"); } finally { System.out.print("C"); //Prints C (finally is always executed) throw new Exception("3"); } } catch (Exception e) { System.out.print(e.getMessage()); //Prints 3 since see (very detailed) link } 

你的问题是非常明显的,答案很简单,同样的程度。 消息为“2”的Exception对象被Exception对象覆盖,消息为“3”。

说明:当一个exception发生时,它抛出的对象被catch块处理。 但是,当catch块本身发生exception时,它的对象将被转移到OUTER CATCH块(如果有),以进行exception处理。 和这里发生的一样。 带有消息“2”的exception对象被传送到OUTER catch块。 但是等待 。在离开内部的try-catch块之前,最后要执行。 这里发生了我们所关心的变化。 一个新的EXCEPTION对象(带有消息“3”)被抛出,或者这个finally块取代了已经抛出的Exception对象(带有消息“2”),结果是当Exception对象的消息被打印时,被覆盖的值,即“3”而不是“2”。

请记住:在CATCH块上只能处理一个exception对象。

finally块总是运行。 要么你从try块内部return ,要么抛出一个exception。 finally块中抛出的exception将覆盖catch分支中抛出的exception。

另外,抛出一个exception本身不会导致任何输出。 该行throw new Exception("2"); 不会写任何东西。

根据你的代码:

 try { try { System.out.print("A"); throw new Exception("1"); // 1 } catch (Exception e) { System.out.print("B"); // 2 throw new Exception("2"); } finally { // 3 System.out.print("C"); // 4 throw new Exception("3"); } } catch (Exception e) { // 5 System.out.print(e.getMessage()); } 

正如你所看到的:

  1. 打印A并抛出exception# 1 ;
  2. 这个例外已经被catch语句和print B - # 2抓住了;
  3. (或者只尝试,如果没有发生任何exception)声明并打印C - # 4并抛出新的exception;
  4. 这个已经被外部捕获语句# 5捕获了;

结果是ABC3 。 与2相同,省略1