Pouvez-vous rompre avec une fermeture Groovy «chacun»?

Est-il possible de break avec une Groovy .each{Closure} , ou devrais-je plutôt utiliser une boucle classique?

Non, vous ne pouvez pas annuler un “chacun” sans lancer une exception. Vous voulez probablement une boucle classique si vous voulez que la pause soit interrompue dans une condition particulière.

Alternativement, vous pouvez utiliser une fermeture “find” au lieu de chaque et retourner true lorsque vous auriez fait une pause.

Cet exemple abandonnera 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 } 

Des tirages

 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ération avec un comportement de pause 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 

Remplacez chaque boucle par une 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 

Non, vous ne pouvez pas quitter une fermeture de Groovy sans lancer une exception. En outre, vous ne devez pas utiliser les exceptions pour le stream de contrôle.

Si vous trouvez que vous voulez sortir d’une fermeture, vous devriez probablement d’abord réfléchir à la raison pour laquelle vous voulez le faire et non à la manière de le faire. La première chose à considérer pourrait être la substitution de la fermeture en question par une des fonctions (conceptuelles) d’ordre supérieur de Groovy. L’exemple suivant:

 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 consortingbue également à la clarté. Il énonce mieux l’intention de votre code.

L'inconvénient potentiel des exemples présentés est que l'itération ne s'arrête qu'au début du premier exemple. Si vous avez des considérations de performances, vous voudrez peut-être l'arrêter tout de suite.

Cependant, pour la plupart des cas d'utilisation qui impliquent des itérations, vous pouvez généralement utiliser l'une des méthodes find, grep, collect, inject, etc. de Groovy. Ils prennent généralement une certaine "configuration" et ensuite "savent" comment faire l'itération pour vous, afin que vous puissiez réellement éviter les boucles impératives dans la mesure du possible.

Juste en utilisant une 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 } 

(1..10) .each {

si (il <5)

l’imprimer

autre

retourner faux

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!