Pouvez-vous rompre avec une fermeture Groovy "chaque"?

Est-il possible de break à partir D'un .each{Closure} Groovy, ou devrais-je utiliser une boucle classique à la place?

129
demandé sur ArtB 2010-06-16 03:25:41

6 réponses

Non, vous ne pouvez pas annuler un "each" sans lancer d'exception. Vous voulez probablement une boucle classique si vous voulez que la pause abandonne dans une condition particulière.

Alternativement, vous pouvez utiliser une fermeture" find " au lieu d'un each et retourner true quand vous auriez fait une pause.

Cet exemple va abandonner avant de traiter toute la liste:

def a = [1, 2, 3, 4, 5, 6, 7]

a.find { 
    if (it > 5) return true // break
    println it  // do the stuff that you wanted to before break
    return false // keep looping
}

Imprime

1
2
3
4
5

Mais n'imprime pas 6 ou 7.

Il est également très facile d'écrire vos propres méthodes d'itérateur avec un comportement de rupture personnalisé qui accepte les fermetures:

List.metaClass.eachUntilGreaterThanFive = { closure ->
    for ( value in delegate ) {
        if ( value  > 5 ) break
        closure(value)
    }
}

def a = [1, 2, 3, 4, 5, 6, 7]

a.eachUntilGreaterThanFive {
    println it
}

Imprime Également:

1
2
3
4
5    
175
répondu Ted Naleid 2010-06-16 01:48:27

Remplacer chaque boucle avec tout fermeture.

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

    println element

    if (element == 3)
        return true // break
}

Sortie

1
3
45
répondu Michal Z m u d a 2013-12-07 17:13:46

Non, vous ne pouvez pas rompre avec une fermeture dans Groovy sans lancer d'exception. En outre, vous ne devriez pas utiliser d'exceptions pour le flux de contrôle.

Si vous vous trouvez vouloir sortir de la fermeture, vous devriez d'abord penser à pourquoi vous voulez faire cela, et non pas comment le faire. La première chose à considérer pourrait être la substitution de la fermeture en question par l'une des fonctions D'ordre supérieur (conceptuelles) de Groovy. La suite exemple:

for ( i in 1..10) { if (i < 5) println i; else return}

Devient

(1..10).each{if (it < 5) println it}

Devient

(1..10).findAll{it < 5}.each{println it} 

Ce qui contribue également à la clarté. Il indique l'intention de votre code beaucoup mieux.

L'inconvénient potentiel dans les exemples montrés est que l'itération ne s'arrête que tôt dans le premier exemple. Si vous avez des considérations de performance, vous voudrez peut-être l'arrêter immédiatement.

Cependant, pour la plupart des cas d'utilisation impliquant des itérations, vous pouvez généralement recourir à L'un des find, grep, collect, inject, etc. de Groovy. méthode. Ils prennent généralement une certaine " configuration "et" savent " comment faire l'itération pour vous, de sorte que vous pouvez réellement éviter la boucle impérative autant que possible.

10
répondu Kai Sternad 2010-06-17 13:43:13

Juste en utilisant la fermeture spéciale

// 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
}
2
répondu sea-kg 2014-03-04 11:32:32

(1..10).chaque{

Si (il

Println il

Else

Renvoie false

-3
répondu Sagar Mal Shankhala 2016-05-22 06:46:31

Vous pourriez casser par RETURN. Par exemple

  def a = [1, 2, 3, 4, 5, 6, 7]
  def ret = 0
  a.each {def n ->
    if (n > 5) {
      ret = n
      return ret
    }
  }

Ça marche pour moi!

-8
répondu Tseveen D 2014-03-13 07:38:08