【问题标题】:Java try..catch & finally [duplicate]Java try..catch 最后[重复]
【发布时间】:2013-09-10 05:42:30
【问题描述】:

我有以下代码:

public class test3    
{
    public static void main(String a[])
    {
        System.out.println("In main");
        System.out.println(new Demo(0).devide());    
    }
}
class Demo
{
    int x;
    Demo(int x)
    {
        this.x=x;
    }
    public int devide()
    {   
        try
        {
            return x/x;
        }
        catch(Exception e)
        {
            System.out.println(e);
            return 4;

        }
        finally
        {
            System.out.println("In finally");
            return 1;
        }    
    }
}

在上面的代码中,我期望 4 作为输出,但生成的输出是:

In main
java.lang.ArithmeticException: / by zero
In finally
1

所以它返回1

【问题讨论】:

标签: java exception try-catch


【解决方案1】:

Final 总是在退出 try/catch 块之前调用,即使 catch 返回。实际上,finally 中的 return 先于 catch 中的返回,catch 中的返回永远不会发生。有关详细信息和说明,请参阅here

基本上,它归结为它被翻译成字节码的方式。 finally 中的代码被视为“子过程”,并且在每个退出点,就在离开 try/catch 块之前,将执行 jsr 跳转到 finally 中的代码。由于子过程跳转不是真正的过程调用,finally 中的return 禁止从子过程返回到它的输入点,因此原始的return 永远不会执行。

divide() 到字节码的粗略翻译可能如下所示:

    aload_0
    getfield   // x
    dup
    idiv
    istore_1
    jsr        // to finally block
    iload_1
    ireturn

// catch
    bipush 4
    istore_1
    jsr        // to finally block
    iload_1
    ireturn

// finally
    astore_2   // save the return address
    bipush 1
    ireturn
    ret 2      // dead code

我们可以清楚地看到为什么 catch 中的 return 从未执行。

【讨论】:

  • exiting the function 是一个误导性的规范。形式上,finally 在退出 try/try-catch 块时执行,这不一定位于方法的边界上。
  • @afk5min 好点,谢谢。
【解决方案2】:

finally 块总是被执行,总是。好吧,也许如果您在 try 中调用 System.exit(0) 就不会了。但在其他情况下,它是 - 无论try / catch 是如何退出(通常或突然)。

finally 的返回值(如果您指定它)覆盖来自 try/catch 的返回值。异常也是如此——如果最终抛出自己的异常,try/catch 中的异常会被丢弃。

【讨论】:

    【解决方案3】:

    如果你的程序执行控制进入try块,就会执行finally块。无论try块是否会无任何异常或任何异常地执行,或者在你使用return语句的try块中,JVM总是会在终止你的之前执行finally块程序。 例如:

     public class test3    
    {
        public static void main(String a[])
        {
            System.out.println("In main");
            System.out.println(new Demo(10).devide());    
        }
    }
    class Demo
    {
        int x;
        Demo(int x)
        {
            this.x=x;
        }
        public int devide()
        {   
            try
            {
                return x/x;
            }
            catch(Exception e)
            {
                System.out.println(e);
                return 4;
    
            }
            finally
            {
                System.out.println("In finally");
                return 1;
            }    
        }
    }
    

    上面的 pgm 将毫无例外地执行,但 finally 块仍然会执行。

    【讨论】:

      【解决方案4】:

      在这种情况下4 也被添加到stack 但最终运行后将返回1。这样你就只能看到 1,因为 1 是堆栈的顶部元素。

      看看这个

       try
          {
              return x/x;
          }
          catch(Exception e)
          {
              System.out.println(e);
              x=4;
              return x++;
      
      
          }
          finally
          {
              System.out.println("In finally");
              return x;
          }
      

      你能看到什么

          In main
          java.lang.ArithmeticException: / by zero
          In finally
          5
      

      现在你可以同时实现捕获和最终返回值,但是我们可以看到堆栈中的顶部元素。

      【讨论】:

        【解决方案5】:

        根据 JLS 14.20.2。 try-finally 和 try-catch-finally 的执行:

        如果try 块的执行由于throw 的值V 而突然完成,那么有一个选择:

        如果V 的运行时类型与try 语句的任何catch 子句的可捕获异常类的赋值兼容,则选择第一个(最左边)这样的catch 子句。将值V 分配给所选catch 子句的参数,并执行该catch 子句的块。然后有一个选择:

        如果catch块正常完成,则finally块被执行。

        【讨论】:

          【解决方案6】:
          In above code I expect 4 as output but output generated is :
          In main
          java.lang.ArithmeticException: / by zero
          In finally
          1
          

          你期待什么?

          Finally 块总是会被执行,除非 JVM 崩溃或者你之前调用了 System.exit()。由于您在 finally 块中返回 1,因此您将获得 1 作为输出。

          【讨论】:

            【解决方案7】:

            会发生以下情况:

            1. 代码到达返回 4;
            2. 值 4 被放入返回栈
            3. 代码到达返回1;
            4. 值 1 被放入返回栈
            5. 方法结束,返回栈顶(因此值为 1)并丢弃值 4。

            【讨论】:

              【解决方案8】:
              finally
              {
              
              }
              

              无论之前是否执行了其他代码,最终都会被执行

              所以,最后它会返回给你1,这实际上是你没想到的 :)

              【讨论】:

                猜你喜欢
                • 2023-01-25
                • 1970-01-01
                • 2014-03-05
                • 2021-01-15
                • 2014-12-18
                • 1970-01-01
                • 1970-01-01
                • 2018-06-24
                • 1970-01-01
                相关资源
                最近更新 更多