我有一个程序如下:
public class Main {
public static void main(String[] args)throws Exception
{
int res = test();
System.out.println("after call , res = " + res) ;
}
public static int test()throws Exception
{
try
{
return 10/0;
}
finally
{
System.out.println("finally") ;
}
}
}
运行以上程序后,在控制台中看到以下结果:
finally
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Main.test(Main.java:17)
at Main.main(Main.java:7)
这种行为是正常的,因为抛出到main方法的异常。
然后我按如下方式更改代码:
public class Main {
public static void main(String[] args)throws Exception
{
int res = test();
System.out.println("after call , res = " + res) ;
}
public static int test()throws Exception
{
try
{
return 10/0;
}
finally
{
System.out.println("finally") ;
return 20;
}
}
}
当在程序上运行时,我在控制台中看到了以下结果:
finally
after call , res = 20
我的问题与第二种格式有关。为什么在finally块中返回时,异常没有抛到main方法?
答案 0 :(得分:13)
当您抛出异常时,会先通过finally
阻止。
如果您的finally
块没有返回或抛出任何内容,则会传递原始异常。
另一方面,如果您的finally
区块返回一个值,则根本不再传播该异常。
答案 1 :(得分:8)
最后看一下try catch的执行情况。
来自java language specification -jls-14.20.2
如果V的运行时类型与try语句的任何catch子句的可捕获异常类不兼容,则执行finally块。然后有一个选择:
如果finally块正常完成,那么try语句会因为抛出值V而突然完成。
如果finally块因为S而突然完成,则try语句突然完成,原因是S(并且值V的抛出被丢弃并被遗忘)。
答案 2 :(得分:7)
来自JLS(强调我的):
如果由于抛出而导致try块的执行突然完成 值V,则有一个选择:
[...]
如果V的运行时类型不与try语句的任何catch子句的可捕获异常类兼容,那么最后 块被执行。然后有一个选择:
如果finally块正常完成,则由于抛出值V,try语句突然完成。
如果finally块因为S而突然完成,则try语句突然完成,原因是S(,值为V的抛出是 丢弃和遗忘)。
这意味着如果return
块中有finally
,则该方法返回时不会抛出异常。
除了return
之外,还有其他状态调用可能导致finally
阻止突然完成并忘记异常。它们在JLS Section 14.1中定义。基本上,它是break
,continue
,return
或异常(抛出或由语句/方法引起)。然后完整的try/catch/finally
块完成了这个原因。
在try/catch/finally
的规范中还有一些案例,特别是如果没有异常或存在匹配的catch子句。它归结为finally
节拍catch
节拍try
。
答案 3 :(得分:3)
return
部分使用finally
,则会失去例外。方法将使用正常类型的返回值完成。return
部分中未使用finally
,则在您的情况下,方法将以例外情况完成。第一种情况:
try {
throw new Exception();
} finally {
//Exception will be lost, normal shutdown of the method
return;
}
第二种情况:
try {
throw new Exception();
} finally {
//Exception won't be lost, we'll get Exception in the main method
}
第三种情况:
try {
throw new Exception();
} finally {
throw new IOException();
// we lost Exception, IOException will be thrown
}
注意:使用finally
部分抛出异常或返回值是不好的做法。例如,已创建此部分以关闭外部资源。
答案 4 :(得分:2)
finally块中的所有内容都在抛出异常之前执行,因此如果返回finally块,则根本不会抛出异常。出于这个原因,从finally块返回通常是一个坏主意。
请查看this blog以获取有关此内容的一些信息。
答案 5 :(得分:0)
Java的return
并不总是返回,this可能会娱乐。
答案 6 :(得分:0)
finally块中的return语句基本上停止了 try块中发生的异常甚至无法传播 虽然它没有被抓住。
但Java编译器在编写这段代码时会发出警告。
虽然(Get-ChildItem -Path . -Filter bin -Recurse | where {$_.psiscontainer} | gci -Filter *test*.dll -Recurse | select -ExpandProperty FullName) -join ' - '
应始终位于return statements
,try block
阻止finally
似乎releasing/closing connections, pointers etc.
的行为方式。
看看here
答案 7 :(得分:0)
如果您阅读了最后的java doc,那么它会说,
它允许程序员避免因返回,继续或中断而意外绕过清理代码。将清理代码放在finally块中总是一种很好的做法,即使没有预期的例外。
因此,如果你在finally块之后放置清理代码,如果有异常则不会被调用。
答案 8 :(得分:0)
在第一种情况下,finally块作为其行为执行,但它没有捕获异常,但是通过main方法抛出异常。通过这个例子检查它
public class HelloWorld{
public static void main(String []args)throws Exception
{
try
{
int res = test();
System.out.println("after call , res = " + res) ;
}
catch(Exception ex)
{
System.out.println("Main Catch") ;
}
}
public static int test()throws Exception
{
try
{
return 10/0;
}
finally
{
System.out.println("finally") ;
}
}
}
在上面的代码中,Main Catch
已执行。
在第二种情况下,您返回了数字,因此main方法中没有例外。
答案 9 :(得分:0)
答案 10 :(得分:0)
在第一个程序中,当在try块中发生ArithmeticException时,然后调用finally块,并在执行finally块之后发生异常。因为异常不是由程序处理的。 第二个程序,当最后一个块执行后,返回语句执行并且没有异常发生,因为在返回语句执行编译器返回main方法后,剩余的执行将不会在finally块中执行。所以不会发生异常。