【问题标题】:Understanding try catch finally with return and value that it returns了解 try catch finally 及其返回的返回值和值
【发布时间】:2014-12-26 20:09:18
【问题描述】:

我有以下代码。

public static void main(String[] args) {
    System.out.println(returnString());
}
private static String returnString(){
    try {
        System.out.println("Executing try");
        return "Return try value";
    } catch (Exception e){
        System.out.println("Executing Catch");
        return "Return catch value";
    } finally {
        System.out.println("Executing finally");
        return "Return finally value";
    }
}

这个的输出是

Executing try
Executing finally
Return finally value

如果我将 finally 块更改为不返回类似的东西

public static void main(String[] args) {
    System.out.println(returnString());
}
private static String returnString(){
    try {
        System.out.println("Executing try");
        return "Return try value";
    } catch (Exception e){
        System.out.println("Executing Catch");
        return "Return catch value";
    } finally {
        System.out.println("Executing finally");
    }
}

那么输出就是

Executing try
Executing finally
Return try value

现在我明白 finally 总是被执行,除非我们调用 system.exit(0);调用或JVM崩溃。 我无法理解的是为什么返回值发生了变化?我仍然希望它返回 try 块的值。
谁能解释为什么要考虑finally值而不是try块的返回值?

请不要回答,因为即使在 try 块中有 return 也会执行 finally ...或者 finally 仅在存在 system.exit(0) 时才执行;调用或JVM崩溃。据我所知。

编辑:

(根据Dirkthis 的评论)
public static void main(String[] args) {
    System.out.println(returnString());
}
private static String returnString(){
    try {
        System.out.println("Executing try");
        return printString("Return try value");
    } catch (Exception e){
        System.out.println("Executing Catch");
        return printString("Return catch value");
    } finally {
        System.out.println("Executing finally");
        return printString("Return finally value");
    }
}

private static String printString(String str){
    System.out.println(str);
    return str;
}

输出:

Executing try
Return try value
Executing finally
Return finally value
Return finally value

【问题讨论】:

  • 因为根据定义,finally 子句在您退出 try 块时都会执行。 System.exit(0) 看起来不像是编译器的出口,它不会抛出异常,因此 finally 无法获得控制权。同样,如果 JVM 崩溃,try 块内没有抛出异常。

标签: java return return-value try-catch-finally


【解决方案1】:

就在从主块返回之前,JVM 必须确保 finally 块被执行,所以它会这样做。这个想法是执行finally 块,然后从主块返回并执行return 语句。但是如果finally 块中有return 语句,那么它将在执行finally 块时执行……这意味着控制永远不会返回到主块来完成return 语句。

  1. JVM 在主块中遇到return 语句。它暂停主块的执行并检查finally 子句。
  2. 它完整地执行finally 子句,包括它的return 语句。
  3. 因此它永远无法完成 try 块。

但请注意,try 块的 return 表达式被评估,然后被丢弃。如果它有副作用,这很重要。所以如果你的主块有return i++,那么这对返回值没有影响,但i仍然会增加。 (感谢Dirk 指出这一点。)

【讨论】:

  • 对表达式 is 求值(特别是会发生副作用)。但它的值将被丢弃(并被finally 子句之一覆盖)
  • @chiastic-security 很好的解释伙伴!
【解决方案2】:

如果你有 return in finally,那就是最后的 return。

这并不奇怪。这是实际行为。返回值在finally 块决定。

如果您在 finally 中没有返回任何内容,那么 将要成为返回值的上一个值 就是返回值(在您的情况下,是 try 块值)。

无论您在 try 中做什么,即使您从 try 块返回,finally 块也会始终执行(如果您在 finally 中有 return,那就是最终返回)。

来自finally docs

运行时系统总是执行 finally 块中的语句不管在 try 块中发生了什么。因此,它是执行清理工作的理想场所。

注意:最终设计为清理。

【讨论】:

    【解决方案3】:

    在Java中,代码:

    try {
      if (foo()) return 1;
    } catch (Exception e){
      if (goo()) return 2;
    } finally {
      if (moo()) return 3;
    }
    

    会被编译器改写成:

    try {
      if (foo())
      {
        if (moo()) return 3;  // Finally code executed before return
        return 1;
      }
    } catch (Exception e){
      if (goo())
      {
        if (moo()) return 3;  // Finally code executed before return
        return 2;
      }
    } catch (Throwable e){
      if (moo()) return 3;   // Finally code executed before re-throw
      throw e;
    }
    if (moo()) return 3;    // Finally code executed before leaving block
    

    基本上,无论是通过returnthrow 还是直接退出,编译器都会在每个会导致代码执行离开受保护块的执行路径中精确地复制finally 块中的代码一次。请注意,虽然某些语言不允许 return within finally 块,但 Java 不允许;但是,如果由于异常而执行了finally 块,则块中的return 可能会导致异常被静默放弃(请查看上面标记为“在重新抛出之前执行的最终代码”的代码;如果return 3; 执行,重新抛出将被跳过)。

    【讨论】:

      猜你喜欢
      • 2018-11-05
      • 2021-05-30
      • 2014-04-27
      • 2013-06-28
      • 2012-02-10
      • 2016-03-28
      • 2011-11-04
      • 2018-01-14
      • 2012-05-20
      相关资源
      最近更新 更多