尝试/最终没有捕获和返回值[重复]

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 中定义。基本上,它是breakcontinuereturn 或异常(抛出或由语句/方法引起)。完整的try/catch/finally 块然后以这个原因完成。

try/catch/finally 的规范中还有一些情况,尤其是在没有异常或存在匹配的catch 子句的情况下。它归结为finallybeats catchbeats 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 块返回一个值,则根本不再传播异常。

参考:JLS about try-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 说:它可以是任何阻止块在其结束括号处结束的语句:A breakcontinuereturn 或异常。【参考方案10】:

finally 块中的所有内容都是在抛出异常之前执行的,所以如果在 finally 块中返回,则根本不会抛出异常。由于这个原因,从 finally 块返回通常是一个坏主意。

查看this blog 了解有关此的一些信息。

【讨论】:

【参考方案11】:

Java 的 return 并不总是返回,this 可能会很有趣。

【讨论】:

以上是关于尝试/最终没有捕获和返回值[重复]的主要内容,如果未能解决你的问题,请参考以下文章

字谜算法返回重复值

Javascript-地图和回调-返回值不受影响[重复]

捕获未经测试的返回值

如何在 cassandra 中捕获条件插入的返回值?

Pandas 映射将所有值返回为 NaN [重复]

正则表达式捕获逗号分隔值