Returning from a finally block in Java
最近我感到惊讶的是,在Java的最后一个块中有一个返回语句是可能的。
似乎很多人都认为这是一件糟糕的事情,如"不要在最后一句中返回"所述。抓取更深一点,我还发现"Java的返回并不总是",这显示了一些非常可怕的例子,其他类型的流控制在最后块。
所以,我的问题是,有人能给我一个例子,在这个例子中,finally块中的返回语句(或其他流控制)产生更好/更可读的代码吗?
几年前,我很难找到由这个原因引起的错误。代码是这样的:
1 2 3 4 5 6 7 8 9 10 |
发生的是在其他代码中抛出了异常。它在
正如其他人所说的,虽然根据Java规范从最终块返回是合法的,但这是一件坏事,不应该做。
您提供的示例是不使用finally中的流控制的充分理由。
即使有一个"更好"的人为例子,也要考虑开发人员,他们必须在以后维护您的代码,并且可能不知道这些细微之处。那个可怜的开发者可能就是你……
如果您使用-xlint:finally,javac将发出返回finally的警告。最初,javac没有发出警告——如果代码有问题,它应该无法编译。不幸的是,向后兼容意味着不能禁止意外的、巧妙的、愚蠢的行为。
可以从finally块抛出异常,但在这种情况下,所展示的行为几乎是您想要的。
向finally块添加控制结构和返回只是"仅仅因为您可以"滥用的另一个例子,这些滥用几乎散布在所有开发语言中。Jason认为这很容易成为维护的噩梦,这是正确的——反对函数早期返回的论点更适用于"延迟返回"的情况。
最后,块的存在有一个目的,允许您在自己之后完全整理,不管前面所有代码中发生了什么。主要是关闭/释放文件指针、数据库连接等,尽管我可以看到它被扩展到说添加定制审计。
影响函数返回的任何内容都应位于try块中。即使您有一个方法检查一个外部状态,执行一个耗时的操作,然后再次检查该状态,以防它变为无效,您仍然希望在try中进行第二次检查-如果它最终位于中,并且长时间操作失败,那么您将不必要地再次检查该状态。
一个简单的groovy测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | public class Instance { List<String> runningThreads = new ArrayList<String>() void test(boolean returnInFinally) { println" test(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"-------------------------------------------------------------------------- " } 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) |
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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 ^^ ----------------------------------------------------------------------------- |
问题:
对我来说,一个有趣的地方是看看groovy是如何处理隐式回报的。在groovy中,只需在末尾留下一个值(不返回),就可以从方法"返回"。如果取消对finally语句中runningthreads.remove(..)行的注释,您认为会发生什么?这会覆盖常规返回值("ok")并覆盖异常吗?!