Wenn Sie eine externe Iteration über eine verwenden, verwenden Iterable
wir break
oder eine return
erweiterte für jede Schleife als:
for (SomeObject obj : someObjects) {
if (some_condition_met) {
break; // or return obj
}
}
Wie können break
oder return
verwenden wir die interne Iteration in einem Java 8-Lambda-Ausdruck wie:
someObjects.forEach(obj -> {
//what to do here?
})
for
Aussage.forEach()
. Die Lösung ist nicht schön, aber es ist möglich. Siehe meine Antwort unten.if
Bedingung innerhalb desforEach
Willens aus.Antworten:
Wenn Sie dies benötigen, sollten Sie nicht verwenden
forEach
eine der anderen in Streams verfügbaren Methoden verwenden. Welches, hängt davon ab, was Ihr Ziel ist.Wenn das Ziel dieser Schleife beispielsweise darin besteht, das erste Element zu finden, das einem Prädikat entspricht:
(Hinweis: Dadurch wird nicht die gesamte Sammlung iteriert, da Streams träge ausgewertet werden. Es wird beim ersten Objekt angehalten, das der Bedingung entspricht.)
Wenn Sie nur wissen möchten, ob die Sammlung ein Element enthält, für das die Bedingung erfüllt ist, können Sie Folgendes verwenden
anyMatch
:quelle
return
Anweisung einerfindSomething
Methode erreicht wird.break
ist in der Regel mit einer Aufnahme während der Bedienung verbunden.forEach
dafür zu erzwingen . Sie sollten stattdessen eine andere, geeignetere Methode verwenden.forEach
" war jedoch technisch falsch. Ich bevorzuge auch Ihre Lösung, kann mir jedoch Anwendungsfälle vorstellen, in denen die in meiner Antwort angegebene Lösung vorzuziehen ist: Wenn die Schleife aufgrund einer echten Ausnahme beendet werden sollte. Ich bin damit einverstanden, dass Sie die Ausnahmen im Allgemeinen nicht zur Steuerung des Flusses verwenden sollten.Dies ist möglich für
Iterable.forEach()
(aber nicht zuverlässig mitStream.forEach()
). Die Lösung ist nicht schön, aber es ist möglich.WARNUNG : Sie sollten es nicht zur Steuerung der Geschäftslogik verwenden, sondern nur zur Behandlung einer Ausnahmesituation, die während der Ausführung der
forEach()
. Wenn eine Ressource plötzlich nicht mehr zugänglich ist, verstößt eines der verarbeiteten Objekte gegen einen Vertrag (z. B. besagt der Vertrag, dass nicht alle Elemente im Stream vorhanden sein dürfen,null
sondern plötzlich und unerwartet eines davonnull
) usw.Gemäß der Dokumentation für
Iterable.forEach()
:Sie lösen also eine Ausnahme aus, die die interne Schleife sofort unterbricht.
Der Code wird ungefähr so sein - ich kann nicht sagen, dass er mir gefällt, aber er funktioniert. Sie erstellen Ihre eigene Klasse,
BreakException
die erweitert wirdRuntimeException
.Beachten Sie, dass
try...catch
es sich nicht um den Lambda-Ausdruck handelt, sondern um die gesamteforEach()
Methode. Um es besser sichtbar zu machen, lesen Sie die folgende Transkription des Codes, die es deutlicher zeigt:quelle
Stream.forEach
dies nicht die gleiche starke Garantie für die Weiterleitung von Ausnahmen an den Anrufer bietet. Daher kann nicht garantiert werden, dass das Auslösen einer Ausnahme auf diese Weise funktioniertStream.forEach
.Iterable.forEach()
, aber ich habe Ihren Punkt nur der Vollständigkeit halber zu meinem Text hinzugefügt.Eine Rendite in einem Lambda entspricht einer Fortsetzung in einem For-Each, aber es gibt kein Äquivalent zu einer Pause. Sie können einfach zurückkehren, um fortzufahren:
quelle
Unten finden Sie die Lösung, die ich in einem Projekt verwendet habe.
forEach
Verwenden Sie stattdessen einfachallMatch
:quelle
Entweder müssen Sie eine Methode verwenden, die ein Prädikat verwendet, das angibt, ob Sie weitermachen möchten (also hat es stattdessen die Pause) oder Sie müssen eine Ausnahme auslösen - was natürlich ein sehr hässlicher Ansatz ist.
Sie könnten also eine
forEachConditional
Methode wie diese schreiben :Stattdessen
Predicate<T>
möchten Sie möglicherweise Ihre eigene funktionale Schnittstelle mit derselben allgemeinen Methode definieren (etwas, das a nimmtT
und a zurückgibtbool
), aber mit Namen, die die Erwartung deutlicher anzeigen -Predicate<T>
ist hier nicht ideal.quelle
takeWhile
Operation, und diese Frage ist nur eine davon, die zeigt, wie sehr das Fehlen der Streams-API zu spüren ist.Sie können java8 + rxjava verwenden .
quelle
Verwenden Sie für maximale Leistung bei parallelen Operationen findAny (), ähnlich wie findFirst ().
Wenn jedoch ein stabiles Ergebnis gewünscht wird, verwenden Sie stattdessen findFirst ().
Beachten Sie auch, dass übereinstimmende Muster (anyMatch () / allMatch) nur boolesche Werte zurückgeben. Sie erhalten kein übereinstimmendes Objekt.
quelle
Update mit Java 9+ mit
takeWhile
:quelle
Ich habe durch so etwas erreicht
quelle
Sie können dies mit einer Mischung aus Peek (..) und anyMatch (..) erreichen.
Anhand Ihres Beispiels:
Oder schreiben Sie einfach eine generische util-Methode:
Und dann benutze es so:
quelle
Was ist mit diesem:
Wo
BooleanWrapper
ist eine Klasse, die Sie implementieren müssen, um den Fluss zu steuern?quelle
!condition.ok()
jedochforEach()
ohnehin nicht verhindert wird, dass alle Objekte durchlaufen werden. Wenn der langsame Teil dieforEach()
Iteration und nicht der Verbraucher ist (z. B. Objekte von einer langsamen Netzwerkverbindung abruft), ist dieser Ansatz nicht sehr nützlich.Es wird nur dort ausgeführt, wo eine Übereinstimmung gefunden wird, und nach der Suche nach Übereinstimmung wird die Iteration gestoppt.
quelle
Ich würde vorschlagen, anyMatch zu verwenden. Beispiel:-
Sie können diesen Beitrag zum Verständnis von anyMatch lesen: - https://beginnersbook.com/2017/11/java-8-stream-anymatch-example/
quelle