Возможно ли выйти из замыкания в groovy

есть ли способ "вырваться" из закрытия groovy.

может быть что-то вроде этого:

[1, 2, 3].each { 
  println(it)
  if (it == 2)
    break 
}

Ответ 1

Вы можете создать исключение:

try {
    [1, 2, 3].each { 
        println(it)
        if (it == 2)
            throw new Exception("return from closure") 
    }
} catch (Exception e) { }

Использование также может использовать "findAll" или "grep" для фильтрации вашего списка, а затем использовать "каждый".

[1, 2, 3].findAll{ it < 3 }.each{ println it }

Ответ 2

Я часто забываю, что Groovy реализует "любой" метод.

[1, 2, 3].any
{   
   println it
   return (it == 2)
}​

Ответ 3

12/05/2013 Тяжело отредактировано.

Отвечая на заданный вопрос.

Можно ли вырваться из закрытия?

Вы можете "вырваться" из закрытия, выпустив ключевое слово return. Однако это не полезно в приведенном примере. Причиной этого является то, что замыкание (подумайте об этом как методе) вызывается методом each для каждого элемента в коллекции.

Если вы запустите этот пример, вы увидите, что он будет печатать 1, затем 3.

[1, 2, 3].each {
  if (it == 2) return
  println(it)
}

Почему break в контексте each не имеет смысла.

Чтобы понять, почему вы не можете вырваться из метода each, как вы могли бы вырваться из цикла for, вам нужно понять немного того, что на самом деле происходит. Вот грубое упрощение того, что делает каждый метод в коллекции.

myEach([0,1,3])

void myEach(List things) {
    for (i in things) {
        myEachMethod(i)
    }
}

void myEachMethod(Object it) { // this is your Closure
    if(it == 2) return
    println it
}

Как вы можете видеть, закрытие - это в основном метод, который можно передать. Как и в java, вы не можете выйти из вызова метода или закрытия.

Что делать, вместо того чтобы ломаться от each.

В Groovy вы должны выразить свой код, используя абстракции высокого уровня, поскольку такой примитивный цикл не является идиоматическим. Для примера, который вы дали, я бы рассмотрел возможность использования findAll. Например:

[1,2,3].findAll { it < 2 }.each { println it }

Надеюсь, это поможет вам понять, что происходит.

Отвечая на подразумеваемый вопрос.

Вы можете вырваться из итераций Collection.each против вашего закрытого закрытия?

Вы не можете вырваться из метода each, не бросая и не вылавливая исключение, как сказал Джон Вагенлейтнер. Хотя я бы сказал, что бросать и ловить исключение во имя управления потоком - это запах кода, а другой программист может хлопнуть ваши руки.

Ответ 5

Попробуйте использовать любой вместо каждый

def list = [1, 2, 3, 4, 5, -1, -2]
list.any { element ->
    if (element > 3)
    return true // break
    println element
}

Результат: 1, 2, 3

Ответ 6

Это в ответ на ответ Джона Вагенлейтера. Ответ Tigerizzy прост. Его можно легко опровергнуть, выполнив первый образец кода или теоретически, прочитав документацию Groovy. Возврат возвращает значение (или значение null без аргумента) из текущей итерации, но не останавливает итерацию. В замыкании он ведет себя как продолжение.

Вы не сможете использовать инъекцию, не понимая этого.

Невозможно "разбить цикл", кроме как выбросить исключение. Использование исключений для этой цели считается вонючим. Итак, как предлагает Wagenleiter, наилучшей практикой является отфильтровать элементы, которые вы хотите перебрать, прежде чем запускать каждого или одного из его кузенов.

Ответ 7

Просто используя специальное закрытие

// declare and implement:
def eachWithBreak = { list, Closure c ->
  boolean bBreak = false
  list.each() { it ->
     if (bBreak) return
     bBreak = c(it)
  }
}

def list = [1,2,3,4,5,6]
eachWithBreak list, { it ->
  if (it > 3) return true // break 'eachWithBreak'
  println it
  return false // next it
}

Ответ 8

Существует другое решение. Хотя, что groovy материал, как каждый /find/any, довольно крут: если он не подходит, не используйте его. Вы все равно можете использовать простой старый

for (def element : list)

В частности, если вы хотите оставить метод тоже. Теперь вы можете использовать continue/break/return как хотите. Получившийся код может быть не крутым, но это легко и понятно.

Ответ 9

С rx-java вы можете преобразовать итерацию в наблюдаемую.

Затем вы можете заменить продолжить фильтр и сломать takeWhile

Вот пример:

import rx.Observable

Observable.from(1..100000000000000000)
          .filter { it % 2 != 1} 
          .takeWhile { it<10 } 
          .forEach {println it}