Lorsque vous utilisez une itération externe sur une boucle que Iterable
nous utilisons break
ou à return
partir de pour chaque boucle améliorée comme:
for (SomeObject obj : someObjects) {
if (some_condition_met) {
break; // or return obj
}
}
Comment pouvons-nous break
ou return
utiliser l' itération interne dans une expression lambda Java 8 comme:
someObjects.forEach(obj -> {
//what to do here?
})
for
déclaration.forEach()
. La solution est pas agréable, mais il est possible. Voir ma réponse ci-dessous.if
condition à l'intérieur duforEach
fera l'affaire.Réponses:
Si vous en avez besoin, vous ne devriez pas utiliser
forEach
, mais l'une des autres méthodes disponibles sur les flux; lequel dépend de votre objectif.Par exemple, si le but de cette boucle est de trouver le premier élément qui correspond à un prédicat:
(Remarque: cela n'itérera pas toute la collection, car les flux sont évalués paresseusement - cela s'arrêtera au premier objet qui correspond à la condition).
Si vous voulez simplement savoir s'il y a un élément dans la collection pour lequel la condition est vraie, vous pouvez utiliser
anyMatch
:la source
return
déclaration d'unefindSomething
méthode.break
est plus généralement associé à un temps de prise en charge.forEach
pour cela; vous devriez plutôt utiliser une autre méthode plus appropriée.forEach
" était techniquement incorrecte. Je préfère également votre solution, mais je peux imaginer des cas d'utilisation où la solution fournie dans ma réponse est préférable: quand la boucle doit être terminée à cause d'une réelle exception. Je suis d'accord que vous ne devriez généralement pas utiliser les exceptions pour contrôler le flux.Ceci est possible pour
Iterable.forEach()
(mais pas de manière fiable avecStream.forEach()
). La solution est pas agréable, mais il est possible.AVERTISSEMENT : vous ne devez pas l'utiliser pour contrôler la logique métier, mais uniquement pour gérer une situation exceptionnelle qui se produit pendant l'exécution de la
forEach()
. Comme une ressource cesse soudainement d'être accessible, l'un des objets traités viole un contrat (par exemple, le contrat dit que tous les éléments du flux ne doivent pas l'êtrenull
mais que soudainement et de manière inattendue l'un d'entre eux l'estnull
), etc.Selon la documentation de
Iterable.forEach()
:Vous lancez donc une exception qui rompra immédiatement la boucle interne.
Le code sera quelque chose comme ça - je ne peux pas dire que je l'aime mais ça marche. Vous créez votre propre classe
BreakException
qui s'étendRuntimeException
.Notez que le
try...catch
n'est pas autour de l'expression lambda, mais plutôt autour de laforEach()
méthode entière . Pour le rendre plus visible, consultez la transcription suivante du code qui le montre plus clairement:la source
Stream.forEach
cela ne fournit pas la même garantie solide que les exceptions sont relayées à l'appelant, donc lever une exception n'est pas garanti pour fonctionner de cette façonStream.forEach
.Iterable.forEach()
, mais j'ai ajouté votre point à mon texte juste pour être complet.Un retour dans un lambda équivaut à une poursuite dans un pour chacun, mais il n'y a pas d'équivalent à une pause. Vous pouvez simplement faire un retour pour continuer:
la source
Vous trouverez ci-dessous la solution que j'ai utilisée dans un projet.
forEach
Utilisez plutôtallMatch
:la source
Soit vous devez utiliser une méthode qui utilise un prédicat indiquant s'il faut continuer (donc il a la pause à la place) ou vous devez lever une exception - ce qui est une approche très laide, bien sûr.
Vous pouvez donc écrire une
forEachConditional
méthode comme celle-ci:Au lieu de cela
Predicate<T>
, vous voudrez peut-être définir votre propre interface fonctionnelle avec la même méthode générale (quelque chose prenant unT
et retournant unbool
) mais avec des noms qui indiquent l'attente plus clairement -Predicate<T>
n'est pas idéal ici.la source
takeWhile
opération classique , et cette question n'est qu'une de celles qui montrent à quel point son manque dans l'API Streams se fait sentir.Vous pouvez utiliser java8 + rxjava .
la source
Pour des performances maximales dans les opérations parallèles, utilisez findAny () qui est similaire à findFirst ().
Cependant, si un résultat stable est souhaité, utilisez plutôt findFirst ().
Notez également que les modèles correspondants (anyMatch () / allMatch) renverront uniquement des booléens, vous n'obtiendrez pas d'objet correspondant.
la source
Mettre à jour avec Java 9+ avec
takeWhile
:la source
J'ai réalisé quelque chose comme ça
la source
Vous pouvez y parvenir en utilisant un mélange de coup d'oeil (..) et anyMatch (..).
En utilisant votre exemple:
Ou écrivez simplement une méthode d'utilisation générique:
Et puis utilisez-le, comme ceci:
la source
Et celui-ci:
Où
BooleanWrapper
est une classe que vous devez implémenter pour contrôler le flux.la source
!condition.ok()
, cependant, cela n'empêche pasforEach()
de boucler sur tous les objets de toute façon. Si la partie lente est l'forEach()
itération et non son consommateur (par exemple, elle obtient des objets d'une connexion réseau lente), cette approche n'est pas très utile.Il ne fera que l'opération où il trouvera la correspondance, et après la recherche de correspondance, il arrêtera son itération.
la source
Je suggère d'utiliser anyMatch. Exemple:-
Vous pouvez consulter cet article pour comprendre anyMatch: - https://beginnersbook.com/2017/11/java-8-stream-anymatch-example/
la source