Podczas korzystania z zewnętrznej iteracji w pętli Iterable
używamy break
lub return
z rozszerzonej dla każdej pętli jako:
for (SomeObject obj : someObjects) {
if (some_condition_met) {
break; // or return obj
}
}
Jak możemy break
lub return
używając wewnętrznej iteracji w wyrażeniu lambda Java 8, takim jak:
someObjects.forEach(obj -> {
//what to do here?
})
for
stwierdzenia.forEach()
. Rozwiązanie nie jest miłe, ale jest możliwe. Zobacz moją odpowiedź poniżej.if
warunek wewnątrzforEach
.Odpowiedzi:
Jeśli potrzebujesz tego, nie powinieneś używać
forEach
, ale jednej z innych metod dostępnych w strumieniach; który zależy od tego, jaki jest twój cel.Na przykład, jeśli celem tej pętli jest znalezienie pierwszego elementu, który pasuje do jakiegoś predykatu:
(Uwaga: nie spowoduje to iteracji całej kolekcji, ponieważ strumienie są leniwie oceniane - zatrzyma się na pierwszym obiekcie spełniającym warunek).
Jeśli chcesz tylko wiedzieć, czy w kolekcji jest element, dla którego warunek jest spełniony, możesz użyć
anyMatch
:źródło
return
instrukcję zfindSomething
metody.break
jest zwykle kojarzony z operacją typu „ take while ”.forEach
; zamiast tego powinieneś użyć innej, bardziej odpowiedniej metody.forEach
” było technicznie niepoprawne. Preferuję również twoje rozwiązanie, ale mogę sobie wyobrazić przypadki użycia, w których rozwiązanie przedstawione w mojej odpowiedzi jest lepsze: kiedy pętla powinna zostać zakończona z powodu prawdziwego wyjątku. Zgadzam się, że ogólnie nie powinieneś używać wyjątków do kontrolowania przepływu.Jest to możliwe
Iterable.forEach()
(ale nie w sposób niezawodnyStream.forEach()
). Rozwiązanie nie jest miłe, ale jest możliwe.OSTRZEŻENIE : Nie należy go używać do kontrolowania logiki biznesowej, lecz wyłącznie do obsługi wyjątkowej sytuacji, która występuje podczas wykonywania
forEach()
. Tak jak zasób nagle przestaje być dostępny, jeden z przetwarzanych obiektów narusza umowę (np. Umowa mówi, że wszystkie elementy w strumieniu nie mogą być,null
ale nagle i nieoczekiwanie jednym z nich jestnull
) itp.Zgodnie z dokumentacją dla
Iterable.forEach()
:Zgłaszasz wyjątek, który natychmiast przerwie wewnętrzną pętlę.
Kod będzie mniej więcej taki - nie mogę powiedzieć, że mi się podoba, ale działa. Tworzysz własną klasę,
BreakException
która się rozszerzaRuntimeException
.Zauważ, że
try...catch
to nie wokół wyrażenie lambda, ale raczej po całymforEach()
metoda. Aby uczynić go bardziej widocznym, zobacz następującą transkrypcję kodu, który pokazuje go wyraźniej:źródło
Stream.forEach
nie nie zapewniają taką samą silną gwarancję o wyjątkami są przekazywane do dzwoniącego, więc rzuca wyjątek nie jest gwarantowane do pracy tę drogęStream.forEach
.Iterable.forEach()
, ale dodałem twój punkt do mojego tekstu tylko dla kompletności.Zwrot w lambda równa się kontynuacji w for-each, ale nie ma odpowiednika przerwy. Możesz po prostu wrócić, aby kontynuować:
źródło
Poniżej znajdziesz rozwiązanie, którego użyłem w projekcie. Zamiast tego
forEach
użyjallMatch
:źródło
Albo musisz użyć metody, która korzysta z predykatu wskazującego, czy kontynuować (więc zamiast tego ma przerwę), albo musisz zgłosić wyjątek - co jest bardzo brzydkim podejściem.
Więc możesz napisać taką
forEachConditional
metodę:Zamiast tego
Predicate<T>
możesz zdefiniować własny interfejs funkcjonalny za pomocą tej samej ogólnej metody (coś biorącT
i zwracając abool
), ale z nazwami, które wyraźniej wskazują na oczekiwania -Predicate<T>
nie jest tutaj idealne.źródło
takeWhile
operacja, a to pytanie jest tylko jednym z tych, które pokazują, jak bardzo odczuwany jest jej brak w interfejsie API strumieni.Możesz użyć java8 + rxjava .
źródło
Aby uzyskać maksymalną wydajność w operacjach równoległych, użyj findAny (), który jest podobny do findFirst ().
Jeśli jednak pożądany jest stabilny wynik, zamiast tego użyj findFirst ().
Zauważ również, że pasujące wzorce (anyMatch () / allMatch) zwrócą tylko wartość logiczną, nie otrzymasz dopasowanego obiektu.
źródło
Zaktualizuj do wersji Java 9+ z
takeWhile
:źródło
Osiągnąłem coś takiego
źródło
Możesz to osiągnąć, używając kombinacji peek (..) i anyMatch (..).
Na twoim przykładzie:
Lub po prostu napisz ogólną metodę util:
A następnie użyj go w następujący sposób:
źródło
A co z tym:
Gdzie
BooleanWrapper
jest klasa, którą należy wdrożyć, aby kontrolować przepływ.źródło
!condition.ok()
jednak nie zapobiega toforEach()
zapętleniu wszystkich obiektów. Jeśli wolna część jestforEach()
iteracją, a nie jej konsumentem (np. Pobiera obiekty z wolnego połączenia sieciowego), to podejście nie jest zbyt przydatne.Wykona operację tylko tam, gdzie znajdzie dopasowanie, a po znalezieniu dopasowania zatrzyma iterację.
źródło
Sugerowałbym użycie anyMatch. Przykład:-
Możesz odnieść się do tego postu, aby zrozumieć anyMatch: - https://beginnersbook.com/2017/11/java-8-stream-anymatch-example/
źródło