从 Java 中的 finally 块返回

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/48088/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:37:41  来源:igfitidea点击:

Returning from a finally block in Java

javaexceptionreturntry-catch-finally

提问by Matt Sheppard

I was surprised recently to find that it's possible to have a return statement in a finally block in Java.

我最近惊讶地发现在 Java 的 finally 块中可以有 return 语句。

It seems like lots of people think it's a bad thing to do as described in 'Don't return in a finally clause'. Scratching a little deeper, I also found 'Java's return doesn't always' which shows some pretty horrible examples of other types of flow control in finally blocks.

似乎很多人认为按照“不要在 finally 子句中返回”中描述的那样做是一件坏事。深入一点,我还发现“ Java 的返回并不总是”,这显示了 finally 块中其他类型的流控制的一些非常可怕的例子。

So, my question is, can anyone give me an example where a return statement (or other flow control) in a finally block produces better / more readable code?

所以,我的问题是,谁能给我一个例子,其中 finally 块中的 return 语句(或其他流控制)产生更好/更易读的代码?

采纳答案by Jason Cohen

The examples you provided are reason enough to notuse flow-control from finally.

您提供的示例足以说明最终使用流控制。

Even if there's a contrived example where it's "better," consider the developer who has to maintain your code later and who might not be aware of the subtleties. That poor developer might even be you....

即使有一个人为的例子,它“更好”,考虑到以后必须维护您的代码并且可能不知道其中的微妙之处的开发人员。那个可怜的开发者甚至可能是你......

回答by Ian

Adding control structures and returns to finally{} blocks are just another example of "just because you can" abuses which are scattered throughout virtually all development languages. Jason was right in suggesting it could easily become a maintenance nightmare - the arguments against early returns from functions apply more-so to this case of "late returns".

添加控制结构并返回到 finally{} 块只是“仅仅因为你可以”滥用的另一个例子,这些滥用几乎遍布所有开发语言。Jason 认为它很容易成为维护的噩梦是正确的 - 反对函数提前返回的论点更适用于这种“延迟返回”的情况。

Finally blocks exist for one purpose, to allow you to completely tidy up after yourself, no matter what happened in all the preceeding code. Principally this is closing / releasing file pointers, database connections etc., though I could see it being stretched to say adding in bespoke auditing.

finally 块的存在是为了一个目的,让您可以完全整理自己,无论前面的所有代码中发生了什么。主要是关闭/释放文件指针、数据库连接等,尽管我可以看到它被延伸到说添加定制审计。

Anything that affects the return of the function should lie in the try{} block. Even if you had a method whereby you checked an external state, did a time consuming operation, then checked that state again in case it became invalid, you would still want the second check inside the try{} - if it sat inside finally{} and the long operation failed, you would then be checking that state a second time needlessly.

任何影响函数返回的东西都应该在 try{} 块中。即使您有一个方法可以检查外部状态,执行一个耗时的操作,然后再次检查该状态以防它无效,您仍然希望在 try{} 中进行第二次检查 - 如果它位于 finally{}并且长时间的操作失败了,然后您将不必要地再次检查该状态。

回答by Tom Hawtin - tackline

javac will warn of return in finally if you use the -Xlint:finally. Originally javac emitted no warnings - if something is wrong with the code, it should fail to compile. Unfortunately backwards compatibility means that unanticipated ingenious foolishness cannot be prohibited.

如果您使用 -Xlint:finally,javac 将警告在 finally 中返回。最初 javac 没有发出警告 - 如果代码有问题,它应该无法编译。不幸的是,向后兼容性意味着无法禁止意外的巧妙愚蠢。

Exceptions can be thrown from finally blocks, but in that case the exhibited behaviour is almost certainly what you want.

异常可以从 finally 块中抛出,但在这种情况下,表现出的行为几乎肯定是您想要的。

回答by John Meagher

I had a REALLY hard time to track down a bug years ago that was caused by this. The code was something like:

几年前,我真的很难找到由此引起的错误。代码是这样的:

Object problemMethod() {
    Object rtn = null;
    try {
        rtn = somethingThatThrewAnException();
    }
    finally {
        doSomeCleanup();
        return rtn;
    }
}

What happened is that the exception was thrown down in some other code. It was being caught and logged and rethrown within the somethingThatThrewAnException()method. But the exception wasn't being propagated up past problemMethod(). After a LONG time of looking at this we finally tracked it down to the return method. The return method in the finally block was basically stopping the exception that happened in the try block from propagating up even though it wasn't caught.

发生的事情是在其他一些代码中抛出了异常。它在方法中被捕获并记录并重新抛出somethingThatThrewAnException()。但是异常并没有被传播过去problemMethod()。经过很长时间的研究,我们终于找到了返回方法。finally 块中的 return 方法基本上阻止了 try 块中发生的异常的传播,即使它没有被捕获。

Like others have said, while it is legal to return from a finally block according to the Java spec, it is a BAD thing and shouldn't be done.

就像其他人所说的那样,虽然根据 Java 规范从 finally 块中返回是合法的,但这是一件糟糕的事情,不应该这样做。

回答by Prof. Ondino

A simple Groovy Test:

一个简单的 Groovy 测试:

public class Instance {

  List<String> runningThreads = new ArrayList<String>()

  void test(boolean returnInFinally) {

    println "\ntest(returnInFinally: $returnInFinally)"
    println "--------------------------------------------------------------------------"
    println "before execute"
    String result = execute(returnInFinally, false)
    println "after execute -> result: " + result
    println "--------------------------------------------------------------------------"

    println "before execute"
    try {
      result = execute(returnInFinally, true)
      println "after execute -> result: " + result
    } catch (Exception ex) {
      println "execute threw exception: " + ex.getMessage()
    }  
    println "--------------------------------------------------------------------------\n"

  }

  String execute(boolean returnInFinally, boolean throwError) {
      String thread = Thread.currentThread().getName()
      println "...execute(returnInFinally: $returnInFinally, throwError: $throwError) - thread: $thread"
      runningThreads.add(thread)
      try {
        if (throwError) {
          println "...error in execute, throw exception"
          throw new Exception("as you liked :-)")
        }
        println "...return 'OK' from execute"
        return "OK"
      } finally {
        println "...pass finally block"
        if (returnInFinally) return "return value from FINALLY ^^"
        // runningThreads.remove(thread)
      }
  }
}

Instance instance = new Instance()
instance.test(false)
instance.test(true)

Output:

输出:

test(returnInFinally: false)
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: false, throwError: false) - thread: Thread-116
...return 'OK' from execute
...pass finally block
after execute -> result: OK
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: false, throwError: true) - thread: Thread-116
...error in execute, throw exception
...pass finally block
execute threw exception: as you liked :-)
-----------------------------------------------------------------------------


test(returnInFinally: true)
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: true, throwError: false) - thread: Thread-116
...return 'OK' from execute
...pass finally block
after execute -> result: return value from FINALLY ^^
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: true, throwError: true) - thread: Thread-116
...error in execute, throw exception
...pass finally block
after execute -> result: return value from FINALLY ^^
-----------------------------------------------------------------------------

Question:

题:

One interesting point for me was to see how Groovy deals with implicit returns. In Groovy it is possible to "return" from a method simply leaving a value at the end (without return). What do you think happens, if you uncomment the runningThreads.remove(..)line in the finally statement - will this overwrite the regular return value ("OK") and cover the exception?!

对我来说有趣的一点是了解 Groovy 如何处理隐式返回。在 Groovy 中,可以从方法中“返回”,只需在末尾留下一个值(不返回)。如果您取消注释finally 语句中的runningThreads.remove(..)行,您认为会发生什么 - 这是否会覆盖常规返回值(“OK”)并覆盖异常?!

回答by Ankur Lathi

Returning from inside a finallyblock will cause exceptionsto be lost.

finally块内部返回将导致exceptions丢失。

A return statement inside a finally block will cause any exception that might be thrown in the try or catch block to be discarded.

finally 块中的 return 语句将导致任何可能在 try 或 catch 块中抛出的异常被丢弃。

According to the Java Language Specification:

根据Java 语言规范:

If execution of the try block completes abruptly for any other reason R, then the finally block is executed, and then there is a choice:

   If the finally block completes normally, then the try statement
   completes  abruptly for reason R.

   If the finally block completes abruptly for reason S, then the try
   statement  completes abruptly for reason S (and reason R is
   discarded).

如果 try 块的执行由于任何其他原因 R 突然完成,则执行 finally 块,然后有一个选择:

   If the finally block completes normally, then the try statement
   completes  abruptly for reason R.

   If the finally block completes abruptly for reason S, then the try
   statement  completes abruptly for reason S (and reason R is
   discarded).

Note: As per JLS 14.17- a return statement always completes abruptly.

注意:根据JLS 14.17- return 语句总是突然完成。