【问题标题】:How does one return from a groovy closure and stop its execution?如何从 groovy 闭包中返回并停止执行?
【发布时间】:2010-10-20 10:03:13
【问题描述】:

我想从闭包中返回,就像在循环中使用 break 语句一样。

例如:

largeListOfElements.each{ element->
    if(element == specificElement){
        // do some work          
        return // but this will only leave this iteration and start the next 
    }
}

在上面的 if 语句中,我想停止遍历列表并离开闭包以避免不必要的迭代。

我见过一个解决方案,在闭包内抛出异常并在外部捕获,但我不太喜欢这种解决方案。

除了更改代码以避免这种算法之外,还有什么解决方案吗?

【问题讨论】:

    标签: groovy closures return


    【解决方案1】:

    我认为您想使用 find 而不是 each(至少对于指定的示例)。闭包不直接支持 break。

    在幕后,groovy 实际上并没有为 find 使用闭包,而是使用了 for 循环。

    或者,您可以编写自己的增强版本的 find/each 迭代器,它接受一个条件测试闭包,如果找到匹配项则调用另一个闭包,如果匹配项满足则中断。

    这是一个例子:

    Object.metaClass.eachBreak = { ifClosure, workClosure -> for (Iterator iter = delegate.iterator(); iter.hasNext();) { def 值 = iter.next() 如果(ifClosure.call(值)){ workClosure.call(值) 休息 } } } def a = ["foo", "bar", "baz", "qux"] a.eachBreak( { it.startsWith("b") } ) { println "正在处理 $it" } // 打印“工作条”

    【讨论】:

      【解决方案2】:

      我认为您正在处理错误的抽象级别。 .each 块正如它所说的那样:它为每个元素执行一次闭包。相反,您可能想要的是使用List.indexOf 找到正确的specificElement,然后在上面做您需要做的工作。

      【讨论】:

      • OP 对他想要什么有点模棱两可:“在上面的 if 语句中,我想停止遍历列表并离开闭包以避免不必要的迭代。”但我强烈怀疑你是对的!尤其重要的是,对于感兴趣的元素之前的元素,没有“做一些工作”的注释。
      【解决方案3】:

      如果您想处理所有元素直到找到特定元素,您还可以执行以下操作:

      largeListOfElements.find { element ->
          // do some work
          element == specificElement
      }
      

      尽管您可以将其与任何类型的“中断条件”一起使用。 我只是用它通过返回来处理集合的前 n 个元素

      counter++ >= n
      

      在结束时。

      【讨论】:

        【解决方案4】:

        据我了解 groovy,缩短此类循环的方法是抛出用户定义的异常。我不知道语法是什么(不是一个 groovy 程序员),但是 groovy 在 JVM 上运行,所以它会是这样的:

        class ThisOne extends Exception {Object foo; ThisOne(Object foo) {this.foo=foo;}}
        
        try { x.each{ if(it.isOk()) throw new ThisOne(it); false} }
        catch(ThisOne x) { print x.foo + " is ok"; }     
        

        【讨论】:

          【解决方案5】:

          在 paulmurray 的回答之后,我不确定自己从闭包中抛出的异常会发生什么,所以我编写了一个易于思考的 JUnit 测试用例:

          class TestCaseForThrowingExceptionFromInsideClosure {
          
              @Test
              void testEearlyReturnViaException() {
                  try {
                      [ 'a', 'b', 'c', 'd' ].each {                 
                          System.out.println(it)
                          if (it == 'c') {
                              throw new Exception("Found c")
                          } 
                      }
                  }
                  catch (Exception exe) {
                      System.out.println(exe.message)
                  }
              }
          }  
          

          上面的输出是:

          a
          b
          c
          Found c
          

          但请记住,“不应使用异常来控制流量”,请特别参阅 Stack Overflow 问题:Why not use exceptions as regular flow of control?

          所以上述解决方案在任何情况下都不太理想。只需使用:

          class TestCaseForThrowingExceptionFromInsideClosure {
          
              @Test
              void testEarlyReturnViaFind() {
                  def curSolution
                  [ 'a', 'b', 'c', 'd' ].find {                 
                      System.out.println(it)
                      curSolution = it
                      return (it == 'c') // if true is returned, find() stops
                  }
                  System.out.println("Found ${curSolution}")
              }
          }  
          

          上面的输出也是:

          a
          b
          c
          Found c
          

          【讨论】:

            【解决方案6】:

            今天我在处理每个闭包时都遇到了类似的问题。我想根据自己的情况中断执行流程,但无法做到。

            在 groovy 中,最简单的方法是在列表中使用 any(),如果您希望基于某些条件返回布尔值,则不要使用每个列表。

            【讨论】:

              【解决方案7】:

              Good ole for 循环在 Groovy 中仍然适用于您的用例

              for (element in largeListOfElements) {
                  if(element == specificElement){
                      // do some work          
                      return
                  }
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-04-16
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2019-08-05
                相关资源
                最近更新 更多