最近我惊讶地发现在Java中的finally块中可以有一个return语句.
似乎很多人认为这样做是不好的,如' 不要在最终条款中返回 '中所描述的那样.更深入地抓了一下,我还发现' Java的回归并不总是 ',这显示了最终块中其他类型的流控制的一些非常可怕的例子.
所以,我的问题是,有人能给我一个例子,其中finally块中的return语句(或其他流控制)产生更好/更可读的代码吗?
几年前,我真的很难找到一个由此造成的错误.代码类似于:
Object problemMethod() { Object rtn = null; try { rtn = somethingThatThrewAnException(); } finally { doSomeCleanup(); return rtn; } }
发生的事情是,在其他一些代码中抛出了异常.它被捕获并记录并在somethingThatThrewAnException()
方法中重新抛出.但是这个例外并没有被传播过去problemMethod()
.经过长时间的观察,我们终于将其追溯到了返回方法.finally块中的返回方法基本上是阻止try块中发生的异常传播,即使它没有被捕获.
就像其他人所说的那样,虽然根据Java规范从finally块返回是合法的,但这是一件坏事,不应该这样做.
您提供的示例有足够的理由不使用最终的流量控制.
即使有一个人为的例子,它"更好",也要考虑开发人员必须在以后维护你的代码并且可能不知道这些细微之处.那个可怜的开发者甚至可能是你......
如果你使用-Xlint,javac将最后警告返回:finally.最初javac没有发出警告 - 如果代码有问题,它应该无法编译.不幸的是,向后兼容性意味着不能禁止意外的愚蠢.
可以从最终块中抛出异常,但在这种情况下,展示的行为几乎肯定是您想要的.
添加控制结构并返回finally {}块只是"仅仅因为你可以"滥用的另一个例子,这些滥用分散在几乎所有的开发语言中.杰森是正确的,暗示它可能很容易成为维护的噩梦 - 反对函数早期回报的论据更多地适用于"迟到的回报".
最后,块存在于一个目的,无论在所有前面的代码中发生了什么,都可以让你完全整理自己.主要是这是关闭/释放文件指针,数据库连接等,虽然我可以看到它被延伸说添加定制审计.
任何影响函数返回的东西都应该在try {}块中.即使您有一个检查外部状态的方法,执行了一个耗时的操作,然后再次检查该状态以防它变为无效,您仍然希望在try {}内部进行第二次检查 - 如果它最终位于{}内如果长时间操作失败,那么你将不必要地再次检查该状态.
public class Instance { ListrunningThreads = new ArrayList () 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)
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")并覆盖异常吗?!