尝试/最终没有捕获和返回值[重复]
Posted
技术标签:
【中文标题】尝试/最终没有捕获和返回值[重复]【英文标题】:try/finally without catch and return value [duplicate] 【发布时间】:2016-01-10 23:31:36 【问题描述】:我有一个程序如下:
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 方法?
【问题讨论】:
这个可能是:***.com/q/48088/1743880? 请看:***.com/questions/48088/… 众所周知,不要在finally
块中使用return
,它不适合这样的事情。如果这样做,异常将被丢弃。
【参考方案1】:
来自JLS(强调我的):
如果 try 块的执行由于抛出 一个值V,那么就有一个选择: [...] 如果 V 的运行时类型与 try 语句的任何 catch 子句的可捕获异常类的赋值不兼容,则 finally 块被执行。然后有一个选择:
如果 finally 块正常完成,则 try 语句会因为抛出 V 值而突然完成。
如果 finally 块由于原因 S 突然完成,则 try 语句由于原因 S 突然完成(并且值 V 的抛出是 丢弃和遗忘)。
这意味着如果您在finally
块内return
,该方法将返回而不抛出异常。
除了return
,还有其他语句会导致finally
块突然完成并忘记异常。它们在JLS Section 14.1 中定义。基本上,它是break
、continue
、return
或异常(抛出或由语句/方法引起)。完整的try/catch/finally
块然后以这个原因完成。
在try/catch/finally
的规范中还有一些情况,尤其是在没有异常或存在匹配的catch 子句的情况下。它归结为finally
beats catch
beats try
。
【讨论】:
【参考方案2】:-
如果在
finally
部分中使用return
,则会丢失异常。方法将以普通类型的返回值结束。
如果您不在finally
部分中使用return
,在您的情况下,方法将异常结束。
第一种情况:
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
部分抛出异常或返回值是一种不好的做法。此部分已创建,例如,用于关闭外部资源。
【讨论】:
【参考方案3】:当您的异常被抛出时,它将首先通过您的finally
块。
如果您的 finally
块没有返回或抛出任何东西,那么原始异常将被传递。
另一方面,如果您的 finally
块返回一个值,则根本不再传播异常。
【讨论】:
【参考方案4】:在第一个程序中,当try块发生ArithmeticException时,调用finally块,执行finally块后,发生异常。因为程序不处理异常。 第二个程序,在该 return 语句执行之后 finally 块执行并且没有发生异常,因为在 return 语句执行之后,编译器在 main 方法中返回,剩余的执行将不会在 finally 块中执行。所以不会发生异常。
【讨论】:
【参考方案5】:因为 finally 块总是被执行,无论是否发生异常,并且 如果你从 finally 返回意味着,你正在将你的执行发送到调用方法和 你失去了例外。所以它也会产生警告。
【讨论】:
【参考方案6】:在第一种情况下,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方法中没有异常。
【讨论】:
【参考方案7】:如果您阅读 finally 的 java 文档,那么它会说,
它允许程序员避免清理代码被return、continue 或break 意外绕过。将清理代码放在 finally 块中始终是一个好习惯,即使没有预料到异常。
所以如果你把清理代码放在 finally 块之后,如果有异常就不会被调用。
【讨论】:
【参考方案8】:finally 块中的 return 语句基本上是停止 try 块中发生的异常甚至无法传播 虽然没被抓到。
但是 Java 编译器在编写这段代码时会通知警告。
尽管return statements
应该始终位于try block
中,而finally
块通常适用于releasing/closing connections, pointers etc.
这似乎是Java
的行为方式。
看看here
【讨论】:
【参考方案9】:看看try catch finally的执行情况。
来自java language specification -jls-14.20.2
如果 V 的运行时类型与 try 语句的任何 catch 子句的可捕获异常类的赋值不兼容,则执行 finally 块。然后有一个选择:
如果 finally 块正常完成,那么 try 语句会因为抛出 V 值而突然完成。
如果 finally 块由于原因 S 突然完成,则 try 语句由于原因 S 突然完成(值 V 的抛出被丢弃并忘记)。
【讨论】:
只是想知道,S 的原因是什么? @bvdb 在这种情况下,例外。 @bvdb JLS 14.1:docs.oracle.com/javase/specs/jls/se8/html/jls-14.html; Sloppy 说:它可以是任何阻止块在其结束括号处结束的语句:Abreak
、continue
、return
或异常。【参考方案10】:
finally 块中的所有内容都是在抛出异常之前执行的,所以如果在 finally 块中返回,则根本不会抛出异常。由于这个原因,从 finally 块返回通常是一个坏主意。
查看this blog 了解有关此的一些信息。
【讨论】:
【参考方案11】:Java 的 return
并不总是返回,this 可能会很有趣。
【讨论】:
以上是关于尝试/最终没有捕获和返回值[重复]的主要内容,如果未能解决你的问题,请参考以下文章