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并关闭两个抛出异常,则方法readFirstLineFromFileWithFinallyBlock抛出finally块抛出的异常;从try块抛出的异常被抑制。为什么这样的行为呢?为什么try块的异常被压制?
答案 0 :(得分:1)
仅处理try
部分内的例外情况。除此之外的任何内容(包括finally
部分)都不会被try
覆盖,因此,不会处理例外情况。
如果要捕获/禁止finally
块内的异常,则需要使用自己的try / catch块包装if (br != null) br.close();
,如下所示:
...
} finally {
try {
if (br != null) br.close();
} catch (Exception e) {
// whatever handling
}
}
...
此外,来自try
块的异常被抑制,因为这是try
块的行为 - 尝试某些东西并让你有机会恢复。由于在try
块之后没有捕获任何异常,因此不会运行任何代码来响应它。
然后,无论是否抛出任何异常,都会执行finally
块。如果它抛出一个异常,并且因为它不在它自己的try / catch块中,它的Exception会传播出方法,并传播给调用方法。
要从下面的评论中获取示例,从Java 7开始,您需要参考the documentation outlined here,并专注于标题为“Supressed”的倒数第二节例外“,基本上表示可以从try
块中抛出多个异常,每个声明的资源最多一个例外。
如果资源声明本身抛出异常会发生什么,我没有安装JDK7,所以我不确定。为什么不将以下代码放在一个测试项目中(与它看起来完全一样,带有伪造的路径),看看会发生什么,然后告诉我们结果对每个人都有什么好处:
try (BufferedReader br = new BufferedReader(new FileReader("a totally invalid path"))) {
return br.readLine();
}
答案 1 :(得分:1)
为什么这样的行为?为什么try块出现异常 supressed?
答案 2 :(得分:0)
因为函数只能抛出一个异常。后来的exceptiobn压制了所有的前任
答案 3 :(得分:0)
那么,你想要什么样的行为?没有同时抛出多个异常的概念 - 因此其中一个例外必须“赢”。如果有一种一致的方式来表示语言中的“多个事情已经出错”(除了将一个例外包装在另一个例外之外),那将是很好的,但船只在那条船上航行。
这是Guava有Closeables.closeQuietly
的原因之一,因此原始异常不会被压制。
编辑:请注意,在Java 7中,try-with-resources功能有更多选项。有关详细信息,请参阅the documentation;它详细介绍了这种具体情况。
答案 4 :(得分:0)
根据规范,它只能抛出一个异常,而“finally”块中的那个异常获胜。
最后,由于这个原因,块总是应该非常防御地编码。参见:
Is a finally block without a catch block a java anti-pattern?
答案 5 :(得分:0)
当我查看这篇文章时,有人在评论中添加了与下面相同的问题。我做了一些分析,这是我的答案。
注释: “该评论包含一个资源尝试声明。你能解释当两个抛出异常时会发生什么吗?”
答案: 它将为try块抛出异常,try-with-resource语句抛出的异常被抑制。
这是一个快速的示例程序来理解它。
class MyResource implements AutoCloseable {
public void close() throws SQLException {
throw new SQLException();
}
}
public class Try {
public static void main(final String[] args) {
try(MyResource mr = new MyResource ()) {
System.out.println("Hi");
throw new IOException();
}
catch (IOException | SQLException e) {
System.out.println("Exception raised:" + e.getClass());
System.out.println("Exception suppressed:" + e.getSuppressed()[0]);
}
}
}
该计划的输出:
您好
异常引发:类java.io.IOException
异常被抑制:java.sql.SQLException