代码之家  ›  专栏  ›  技术社区  ›  Matt Sheppard

从Java中的finally块返回

  •  156
  • Matt Sheppard  · 技术社区  · 16 年前

    似乎很多人都认为这是一件坏事 Don't return in a finally clause “再深一点,我也发现” Java's return doesn't always '这显示了一些非常可怕的例子,其他类型的流量控制在最后块。

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

    5 回复  |  直到 5 年前
        1
  •  160
  •   Flow Matt McDonald    8 年前

    几年前,我真的很难找到一个由这个引起的bug。代码类似于:

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

    somethingThatThrewAnException() 方法但是这个例外并没有被传播到过去 problemMethod() . 经过长时间的研究,我们终于找到了返回方法。finally块中的返回方法基本上是阻止try块中发生的异常向上传播,即使它没有被捕获。

    正如其他人所说,虽然根据Java规范从finally块返回是合法的,但这是一件坏事,不应该这样做。

        2
  •  94
  •   Jason Cohen    16 年前

    你提供的例子足以说明

    即使有一个设计得更好的例子,也要考虑开发人员以后必须维护代码,谁可能不知道这些细微之处。那个可怜的开发人员可能就是你。。。。

        3
  •  23
  •   Tom Hawtin - tackline    16 年前

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

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

        4
  •  13
  •   Ian    16 年前

    添加控制结构并返回到finally{}块只是“just-because-you-can”滥用的另一个例子,这种滥用几乎散布在所有开发语言中。Jason正确地指出,这很容易成为维护的噩梦——反对函数提前返回的论点更适用于“延迟返回”的情况。

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

        5
  •  6
  •   Prof. Ondino    13 年前

    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)
    

    输出:

    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中,只需在末尾留下一个值(不返回),就可以从方法“返回”。如果取消注释 运行线程。删除(..)

        6
  •  2
  •   Ankur Lathi    5 年前

    从内部返回 finally 阻塞将导致 exceptions

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

    Java Language Specification:

    如果try块的执行由于任何其他原因突然完成

       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).
    

    JLS 14.17 -return语句总是突然完成。