【问题标题】:Why is printed 1?为什么打印 1?
【发布时间】:2013-10-29 07:11:28
【问题描述】:

我有代码:

class Test {
  public static void main(final String [] args) {
    System.out.println(foo());
  }

  private static int foo() {
    int a = 0;
      try {
        ++a;
        return a;
      } finally {
        a = 10;
      }
    }
  }

我不明白为什么要打印 1。

【问题讨论】:

标签: java try-finally


【解决方案1】:
try {
    ++a;
    return a; // 1 is returned here
} finally {
    a = 10; // a is assigned with 10 later.
}

a 的值递增并在try 块本身中返回。发布此returna 的值在finally 块中重新分配。这就是它打印 1 的原因。


引用docs。这应该可以帮助您更清楚地理解它。

最终编译

try-finally 语句的编译类似于 try-catch。在将控制转移到 try 语句之外之前,无论该转移是正常的还是突然的,因为抛出了异常,都必须首先执行 finally 子句。对于这个简单的例子:

void tryFinally() {
    try {
        tryItOut();
    } finally {
        wrapItUp();
    }
}

编译后的代码是:

Method void tryFinally()
0   aload_0             // Beginning of try block
1   invokevirtual #6    // Method Example.tryItOut()V
4   jsr 14              // Call finally block
7   return              // End of try block
8   astore_1            // Beginning of handler for any throw
9   jsr 14              // Call finally block
12  aload_1             // Push thrown value
13  athrow              // ...and rethrow value to the invoker
14  astore_2            // Beginning of finally block
15  aload_0             // Push this
16  invokevirtual #5    // Method Example.wrapItUp()V
19  ret 2               // Return from finally block
Exception table:
From    To      Target      Type
0       4       8           any

在try语句之外有四种控制传递方式:

  1. 从那个方块的底部掉下来
  2. 通过返回
  3. 通过执行 break 或 continue 语句
  4. 通过引发异常。

【讨论】:

  • 这怎么可能?返回后如何分配新值?
  • 这不是真的,主要原因是它们在不同的块中。如果您在同一块中执行相同操作,您将看到编译器错误。 @frostjogla 看看我的编辑。
  • @R.J 我知道 finally 块总是在 try 块之后执行。我无法 uderstat 怎么可能?这个JVM是怎么做的?
  • 我已经编辑了答案以添加文档的某些部分。希望对您有所帮助。
【解决方案2】:

这是因为 try..catch..finally 中的 finally 块在 try..catch 中的代码完成后运行

finally 中为您分配了值,在此之前您在try 中返回

finally中的代码总是会执行,但是你已经返回了try中的值。

try {
    ++a;
    return a; 
  } finally {
    a = 10; 
  }

现在a 的值是10,在return 之后。 虽然不是一个好的做法,但只是为了演示。

int a= 0;
try {
    ++a;
    return a; 
  } finally {
    a = 10;
    return a;
  }

现在是return10

编辑:

您的疑问:为什么不出现无法解决的错误?

try-catch-finally 中的块是不同的。在同一块中执行相同的操作,然后查看。

try {
            ++a;
            return a;
            a=100;  //compiler error.
          } finally {
            a = 10;
          }

编辑2

来自java language specification of try-catch-finally :

try 语句执行一个块。如果抛出一个值并且 try 语句有一个或多个可以捕获它的 catch 子句,则控制将转移到第一个这样的 catch 子句。如果 try 语句有 finally 子句,则执行另一个代码块,无论 try 块是正常完成还是突然完成,也不管 catch 子句是否首先被赋予控制权。

【讨论】:

  • 这怎么可能?返回后如何分配新值?
  • @frostjogla 在 try-catch-finally 中的块是不同的。在同一个块中做同样的事情,看看。看看我的编辑部分。
【解决方案3】:
class Test {
  public static void main(final String [] args) {
    System.out.println(foo());
  }

  private static int foo() {
    int a = 0;
      try {
        ++a;
        return a;
      } finally {
        a = 10;
      }
    }
  }

在上面的代码中,返回的值将是 1,因为 finally 不会更新 try 块中返回的值。

class Test {
  public static void main(final String [] args) {
    System.out.println(foo());
  }

  private static int foo() {
    int a = 0;
      try {
        ++a;
        return a;
      } finally {
        a = 10;
    return a;
      }
    }
  }

上面的代码会返回10,因为这个值又是从finally返回的。

【讨论】:

    【解决方案4】:

    JVM 是基于堆栈的机器。它将值推送和弹出到堆栈上。我反编译了Test 类,以了解它是如何工作的。

    private static int foo();
     Code:
       0: iconst_0        //push 0 to stack
       1: istore_0        //store 0 in the local variable 'a'(numbered 0). a==0
       2: iinc      0, 1  //increase the local variable 'a'(numbered 0) by 1. a==1;
       5: iload_0         //push value of the local variable 'a' onto the stack;
       6: istore_1        //store 1 in the local variable that not be declared(numbered 1);
       7: bipush    10    //push 10 onto the stack;
       9: istore_0        //store 10 in the local variable 'a'
      10: iload_1         //push onto stack value==1 of local variable that not be declared
      11: ireturn         //return 1
      12: astore_2
      13: bipush   10
      15: istore_0
      16: aload_2
      17: athrow
     Exception table:
     // not interesting ...
    

    【讨论】:

      【解决方案5】:

      只是...你没有提到 return a infinal block。 最终块在最后执行并且 a 的值设置为 10,但是您还没有编码来返回这个新值! 尝试下面的代码以获得您的预期输出:

      class Test {
        public static void main(final String [] args) {
          System.out.println(foo());
        }
      
        private static int foo() {
          int a = 0;
            try {
              ++a;
              return a;
            } finally {
              a = 10;
             return a;
            }
          }
        }
      

      【讨论】:

        猜你喜欢
        • 2013-07-11
        • 2021-04-03
        • 1970-01-01
        • 2013-12-14
        • 2017-08-29
        • 1970-01-01
        • 1970-01-01
        • 2017-03-02
        • 2014-08-04
        相关资源
        最近更新 更多