今天在大学时我们谈了try
,catch
和finally
。
我对这两个例子感到困惑:
PrintWriter out = null;
try {
out = new PrintWriter(...); // We open file here
} catch (Exception e) {
e.printStackTrace();
} finally { // And we close it here
out.close();
}
关闭finally
中的文件与我们是否这样做有什么区别:
PrintWriter out = null;
try {
out = new PrintWriter(...); // We open file here
} catch (Exception e) {
e.printStackTrace();
}
out.close();
catch之后的这段代码将始终执行。
您能否给我一些很好的例子,说明我们何时使用finally
和何时将代码放在catch之后的差异?我知道最终将永远执行,但程序也会在catch块之后继续运行。
答案 0 :(得分:33)
如果代码抛出Error
,它仍然会有所不同。这不会在代码中捕获,因此try/catch/finally
之后的任何部分都不会被捕获。如果它是finally
的一部分,即使Error
也会执行。
其次,如果由于某种原因e.printStackTrace()
抛出异常(虽然它非常罕见),同样会发生 - finally
仍然会被执行。
一般来说,finally
是释放资源的非常安全的方式,无论发生什么。从Java 7开始支持try-with-resources更加安全,因为它可以轻松管理在关闭操作期间抛出的多个异常。在这个例子中,它看起来像:
try (PrintWriter out = new PrintWriter(...)) {
// do whatever with out
}
catch (Exception e) {
e.print... (whatever)
}
// no need to do anything else, close is invoked automatically by try block
编辑:还要注意你的代码不是真的正确(无论哪个版本)。如果PrintWriter
构造函数引发异常,则行out.close()
将在NullPointerException
上失败。
答案 1 :(得分:3)
如果在try
块中发生未被捕获的错误,或者即使在catch
块中发生错误,也不会执行catch之后的'code of code',而是{阻止{1}}阻止。
finally
将永远执行。
来自Java文档:
当try块退出时,finally块始终执行。这个 确保即使意外发生也执行finally块 异常发生。但最终对于不仅仅是异常更有用 处理 - 它允许程序员避免使用清理代码 被意外绕过返回,继续或休息。进行清理 finally块中的代码总是很好的做法,即使没有 预计有例外。
答案 2 :(得分:2)
如果catch块中的某些内容会抛出异常怎么办? out.close不会执行。您还可以使用" try with resources"确保所有资源在使用后关闭。试试这个例子:
public static void withFinnaly() {
try {
throwException();
System.out.println("This won't execute");
} catch (Exception e) {
System.out.println("Exception is caught");
throwException();
} finally {
System.out.println("Finally is always executed," +
" even if method in catch block throwed Exception");
}
}
public static void withOutFinnaly() {
try {
throwException();
System.out.println("This won't execute");
} catch (Exception e) {
System.out.println("Exception is caught");
throwException();
}
System.out.println("Looks like we've lost this... " +
"This wont execute");
}
public static void throwException() throws RuntimeException {
throw new RuntimeException();
}
答案 3 :(得分:2)
finally的正常用例是当您不想在同一方法中捕获异常时。
在这种情况下,你使用finally块的try而没有catch。这样,您可以确保关闭资源,而不必在方法本身中捕获异常。
答案 4 :(得分:2)
在Java中,源代码:
void foo()
{
try {
if (W())
return;
}
catch (FooException ex) {
if (X())
throw;
}
finally {
Y();
}
Z();
}
将由编译器转换为:
void foo()
{
try {
if (W()) {
Y();
return;
}
}
catch (FooException ex) {
if (X()) {
Y();
throw;
}
}
catch {
Y();
throw;
}
Y();
Z();
}
效果是导致Finally块中的代码被复制
所有控制可能离开方法的地方。任何try
块
具有finally
但不是catch-all处理程序的处理程序相当于一个具有立即抛出的catch-all处理程序的处理程序(然后处理器可以在catch-all之前插入finally
代码的副本处理程序。
答案 5 :(得分:1)
如果在NullPointerException
的构造函数中发生异常,您的第二个示例可能会抛出不需要的PrintWriter
。
另一种可能性是out.close();
会抛出错误,而不会被捕获。
如果将代码移动到finally
块,它将始终执行 - 无论try块是否成功。如果您的try
- 块引发未捕获的异常,则尤其非常有用。在第二个示例中,这将导致out.close()
未被执行,而对于finally块,即使try
块引发未被捕获的错误,也会执行它。
答案 6 :(得分:1)
虽然答案本身不完整,但try-finally
(mis)使用的这两个例子可能具有启发性:
public class JavaApplication3
{
static int foo()
{
try
{
return 6;
}
finally
{
return 4;
}
}
public static void main(String[] args)
{
System.out.println("foo: " + foo());
}
}
public class JavaApplication3
{
static int foo()
{
try
{
throw new Exception();
}
finally
{
return 4;
}
}
public static void main(String[] args)
{
System.out.println("foo: " + foo());
}
}
两个程序都输出 4 。
上找到原因首先执行try块,执行带有finally块的try语句。然后有一个选择:
•如果由于抛出值而导致try块的执行突然完成 V,然后有一个选择:
[...]
- 如果V的运行时类型与可捕获的分配不兼容 try语句的任何catch子句的异常类,然后是finally 块被执行。然后有一个选择:
[...]
> 如果finally块因为S而突然完成,那么try语句 由于原因S突然完成(并且丢弃值V的抛出并且 忘了)。•如果由于任何其他原因R 突然完成try块的执行,则执行finally块,然后有一个选择:
- 如果finally块正常完成,则try语句完成 因为理由而突然出现 - 如果finally块因为S而突然完成,那么try语句 由于原因S突然完成(原因R被丢弃)。
编辑我的
考虑return
是完成try
或finally
阻止的突然方法。
答案 7 :(得分:0)
一个较小的例子:
PrintWriter out = null;
try {
out = new PrintWriter();
out.print(data);
} finally {
out.close();
}
在这里,我们不会发现任何异常(由来电者处理),但我们确实希望close
作者是否
try
块或在这两种情况下,finally
中的代码都是作为离开块的一部分执行的。
在这里,我们捕获了一些例外情况:
PrintWriter out = null;
try {
out = new PrintWriter();
out.print(data);
} catch (IOException e) {
log(e);
} finally {
out.close();
}
do_something_else();
这里有三种可能的途径:
try
部分,然后是finally
,然后是do_something_else()
,try
部分抛出IOException
,捕获并记录,然后finally
块运行,然后do_something_else()
或try
部分抛出一个不同的throwable,它没有被捕获,但是finally
块运行,然后代码跳转到下一个封闭的try
,可能在调用者中。 / LI>
在编写finally
块时要小心 - 它不在try
内,因此任何例外情况都会先于任何正在进行的异常。简短的建议是尽量避免可能从finally
或catch
内部抛出的东西。