未捕获Java异常?

未捕获Java异常?,java,exception,try-catch,Java,Exception,Try Catch,我对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 {

我对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(经过测试,确实如此)


我的问题是,异常(“2”)去了哪里?

在finally块中抛出的异常抑制了在try或catch块中先前抛出的异常

Java 7示例:

例如:


但是,在本例中,如果方法readLine和close都抛出 异常,则方法readFirstLineFromFileWithFinallyBlock 抛出从finally块抛出的异常;例外 禁止从try块抛出


Java7新的
try-with
语法添加了异常抑制的另一个步骤:try块中抛出的异常抑制前面在try-with部分中抛出的异常

从同一个例子:

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块抛出,最多可以抛出两个异常 从尝试关闭时的try with resources语句 ZipFile和BufferedWriter对象。如果从 try块,并从 请尝试使用resources语句,然后从 try with resources语句被抑制,并引发异常 块旁边是由 writeToFileZipFileContents方法。您可以检索这些文件 通过从 try块引发的异常


在问题中的代码中,每个块都明显地丢弃了旧的异常,甚至没有记录它,当您试图解决一些bug时,这是不好的:

来自:

如果catch块由于原因R而突然完成,则执行finally块。还有一个选择:

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

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

因此,当存在抛出异常的catch块时:

try {
    // ...
} catch (Exception e) {
    throw new Exception("2");
}
} finally {
    throw new Exception("3");
}
但还有一个finally块也会引发异常:

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

异常(“2”)
将被丢弃,并且只有
异常(“3”)
将被传播。

因为
抛出新异常(“2”)
catch
块抛出,而不是
try
,它将不会被再次捕获。
请参见

事情就是这样:

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
}

finally
块始终运行。要么从try块内部返回
,要么抛出异常。
finally
块中抛出的异常将覆盖catch分支中抛出的异常


此外,引发异常本身不会导致任何输出。行
抛出新异常(“2”)
不会写出任何东西。

你的问题很明显,答案也很简单。。 消息为“2”的异常对象被消息为“3”的异常对象覆盖。

说明: 当异常发生时,它会将其对象抛出catch块来处理。但当catch块本身发生异常时,它的对象被转移到外部catch块(如果有)进行异常处理。这里也发生了同样的事情。带有消息“2”的异常对象被传输到外部catch块但请等待。。在离开内部try-catch块之前,它必须最终执行。这里发生了我们所关心的变化。抛出一个新的异常对象(带有消息“3”)或此finally块,该块替换了已抛出的异常对象(带有消息“2”)。因此,当打印异常对象的消息时,我们得到了覆盖值,即“3”,而不是“2”


请记住:on CATCH块只能处理一个异常对象。

根据您的代码:

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
  • 此异常捕获了catch语句并打印
    B-#2
  • block finally
    #3
    在try-catch(或者只有try,如果没有发生任何异常)语句之后执行,并打印
    C-#4
    和抛出新异常
  • 这一个已被外部catch语句捕获
    结果是
    ABC3
    。而
    2
    的省略方式与
    1

    相同,这甚至适用于
    return
    语句。如果finally块有返回,它将覆盖
    try
    catch
    块中的任何返回。由于这些“特性”,一个很好的实践是finally块不应该抛出异常或返回语句。这也是在Java7中使用资源try with resources所具有的继承优势。如果在关闭资源时生成辅助异常,它会保留初始异常,这通常会使调试更容易。是的,我看到了这种情况,但我正在寻找解释-为什么它会这样做是的,我知道自己不会抛出异常输出,但我不知道原因,为什么应该删除异常2。我又聪明了一点:-)总是很长的时间,在很长的时间内任何事情都可能发生(检查谜题)+1啊,伙计,我知道这个答案。我在一次采访中被问到这个问题。对于理解try/catch/finally如何在堆栈上工作来说,这是一个非常好的问题。只有一个print语句可以打印数字(最后一个:
    print(e.getMessag))