Est-il possible de break
à partir d'un Groovy .each{Closure}
, ou devrais-je utiliser une boucle classique à la place?
Non, vous ne pouvez pas abandonner un "chacun" sans lever une exception. Vous voulez probablement une boucle classique si vous voulez que la pause soit annulée dans certaines conditions.
Alternativement, vous pouvez utiliser une fermeture "trouver" au lieu d'une fermeture individuelle et renvoyer true lorsque 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
}
Impressions
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é acceptant 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 aussi:
1
2
3
4
5
Remplacez la boucle each par la fermeture any.
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 rompre avec une fermeture à Groovy sans lever une exception. De plus, vous ne devriez pas utiliser d'exceptions pour le flux de contrôle.
Si vous avez envie de sortir d'une fermeture, vous devriez probablement commencer par vous demander pourquoi vous voulez le faire et non pas comment le faire. La première chose à considérer pourrait être la substitution de la fermeture en question à l’une des fonctions de Groovy (conceptuelles) d’ordre supérieur. 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 contribue également à la clarté. Cela énonce beaucoup mieux l'intention de votre code.
L'inconvénient potentiel des exemples présentés est que l'itération ne s'arrête que tôt dans le premier exemple. Si vous avez des problèmes de performances, vous voudrez peut-être l'arrêter immédiatement.
Toutefois, dans la plupart des cas d'utilisation impliquant des itérations, vous pouvez généralement recourir à l'une des méthodes de recherche, grep, collecte, injection, etc. de Groovy. Ils prennent généralement quelques "configurations" puis "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
}