Czy istnieje operacja strumienia Java 8, która ogranicza (potencjalnie nieskończony), Stream
dopóki pierwszy element nie dopasuje predykatu?
W Javie 9 możemy użyć takeWhile
jak w poniższym przykładzie, aby wydrukować wszystkie liczby mniejsze niż 10.
IntStream
.iterate(1, n -> n + 1)
.takeWhile(n -> n < 10)
.forEach(System.out::println);
Ponieważ w Javie 8 nie ma takiej operacji, jaki jest najlepszy sposób na jej ogólne wdrożenie?
java
java-8
java-stream
MForster
źródło
źródło
IntStream.iterate(1, n->n<10, n->n+1).forEach(System.out::print);
Odpowiedzi:
Taka operacja powinna być możliwa w Javie 8
Stream
, ale niekoniecznie musi być wykonana wydajnie - na przykład niekoniecznie trzeba równolegle wykonywać taką operację, ponieważ trzeba patrzeć na elementy w kolejności.Interfejs API nie zapewnia łatwego sposobu na zrobienie tego, ale prawdopodobnie najłatwiej jest to zrobić
Stream.iterator()
, owiń je,Iterator
aby mieć implementację „take-while”, a następnie wróć do a,Spliterator
a następnie aStream
. Lub - może - owinąćSpliterator
, chociaż tak naprawdę nie można go już podzielić w tej implementacji.Oto niesprawdzone wdrożenie
takeWhile
na zasadzieSpliterator
:źródło
Operacje
takeWhile
idropWhile
zostały dodane do JDK 9. Twój przykładowy kodzachowuje się dokładnie tak, jak się tego spodziewasz po skompilowaniu i uruchomieniu pod JDK 9.
JDK 9 został wydany. Można go pobrać tutaj: http://jdk.java.net/9/
źródło
takeWhile
/dropWhile
: download.java.net/jdk9/docs/api/java/util/stream/Stream.htmltakeWhile
idropWhile
zamiastlimitWhile
iskipWhile
, dla zachowania spójności z istniejących API?takeWhile
idropWhile
są dość rozpowszechnione, występują w Scali, Python, Groovy, Ruby, Haskell i Clojure. Asymetria zskip
ilimit
jest niefortunne. Możeskip
ilimit
powinienem był zadzwonićdrop
itake
, ale nie są one tak intuicyjne, chyba że znasz już Haskella.dropXXX
itakeXXX
są bardziej popularnymi terminami, ale mogę osobiście żyć z bardziej SQL-esquelimitXXX
iskipXXX
. Uważam, że ta nowa asymetria jest bardziej myląca niż indywidualny wybór terminów ... :) (przy okazji: Scala też madrop(int)
itake(int)
)allMatch()
jest funkcją zwierającą, więc możesz jej użyć do zatrzymania przetwarzania. Główną wadą jest to, że musisz zrobić test dwa razy: raz, aby sprawdzić, czy powinieneś go przetworzyć, i jeszcze raz, aby sprawdzić, czy kontynuować.źródło
Stream.allMatch()
jest to operacja zwarcia . To się zakończy nawet w nieskończonym strumieniu, takim jakIntStream.iterate()
. Oczywiście z perspektywy czasu jest to rozsądna optymalizacja.peek
. Gdybym go spotkał w przyszłym miesiącu, zastanawiałbym się, dlaczego programista przede mną sprawdził, czyallMatch
zignorował odpowiedź.W odpowiedzi na odpowiedź @StuartMarks . Moja biblioteka StreamEx ma
takeWhile
operację zgodną z bieżącą implementacją JDK-9. Podczas pracy pod JDK-9 po prostu deleguje się do implementacji JDK (przezMethodHandle.invokeExact
co jest naprawdę szybki). Podczas pracy pod JDK-8 zostanie zastosowana implementacja „polyfill”. Korzystając z mojej biblioteki, problem można rozwiązać w następujący sposób:źródło
takeWhile
jest jedną z funkcji udostępnianych przez bibliotekę protonpack .źródło
Aktualizacja: Java 9 jest
Stream
teraz wyposażona w metodę takeWhile .Nie potrzeba hacków ani innych rozwiązań. Po prostu użyj tego!
Jestem pewien, że można to znacznie poprawić: (ktoś może sprawić, że będzie wątkowo bezpieczny)
Na pewno hack ... Nie elegancki - ale działa ~: D
źródło
Możesz użyć java8 + rxjava .
źródło
W rzeczywistości są 2 sposoby na zrobienie tego w Javie 8 bez żadnych dodatkowych bibliotek lub przy użyciu Java 9.
Jeśli chcesz wydrukować numery od 2 do 20 na konsoli, możesz to zrobić:
lub
Dane wyjściowe są w obu przypadkach:
Nikt nie wspomniał anyMatch jeszcze. To jest powód tego postu.
źródło
Jest to źródło skopiowane z JDK 9 java.util.stream.Stream.takeWhile (Predicate). Mała różnica w pracy z JDK 8.
źródło
Oto wersja wykonana na ints - jak zadano w pytaniu.
Stosowanie:
Oto kod StreamUtil:
źródło
Idź po bibliotekę AbacusUtil . Zapewnia dokładnie taki interfejs API, jaki chcesz i więcej:
Deklaracja : Jestem programistą AbacusUtil.
źródło
Nie można przerwać strumienia, z wyjątkiem operacji terminalu powodującego zwarcie, która pozostawiłaby niektóre wartości strumienia nieprzetworzone niezależnie od ich wartości. Ale jeśli chcesz uniknąć operacji na strumieniu, możesz dodać transformację i filtrować do strumienia:
To przekształca strumień rzeczy w wartości zerowe, gdy rzeczy spełniają pewien warunek, a następnie odfiltrowuje wartości zerowe. Jeśli chcesz pozwolić sobie na efekty uboczne, możesz ustawić wartość warunku na true po napotkaniu czegoś, aby wszystkie kolejne rzeczy były odfiltrowywane bez względu na ich wartość. Ale nawet jeśli nie, możesz zaoszczędzić dużo (jeśli nie całkiem) przetwarzania, odfiltrowując wartości ze strumienia, którego nie chcesz przetwarzać.
źródło
Nawet ja miałem podobne wymaganie - wywołaj usługę internetową, jeśli się nie powiedzie, spróbuj ponownie 3 razy. Jeśli nie powiedzie się nawet po wielu próbach, wyślij powiadomienie e-mailem. Po google dużo,
anyMatch()
przyszedł jako wybawiciel. Mój przykładowy kod w następujący sposób. W poniższym przykładzie, jeśli metoda webServiceCall zwróci wartość true w samej pierwszej iteracji, strumień nie będzie iterował dalej, tak jak to wywołaliśmyanyMatch()
. Wierzę, że tego właśnie szukasz.źródło
Jeśli znasz dokładną liczbę powtórzeń, które zostaną wykonane, możesz to zrobić
źródło
zamiast piku możesz użyć mapToObj, aby zwrócić końcowy obiekt lub komunikat
źródło
Jeśli masz inny problem, może być potrzebne inne rozwiązanie, ale w przypadku obecnego problemu po prostu wybrałbym:
źródło
Może być trochę off topic, ale to, co mamy na
List<T>
raczej niżStream<T>
.Najpierw musisz mieć
take
metodę util. Ta metoda wymaga pierwszychn
elementów:po prostu działa jak
scala.List.take
teraz napisanie
takeWhile
metody opartej na . będzie dość prostetake
to działa tak:
ta implementacja kilkukrotnie iteruje listę częściowo, ale nie doda
O(n^2)
operacji dodawania . Mam nadzieję, że to możliwe.źródło
Mam inne szybkie rozwiązanie, wdrażając to (co jest raczej nieczyste, ale masz pomysł):
źródło
current
nigdy.equals(e)
nie dostaniesz nieskończonej pętli. Oba, nawet jeśli później złożysz wniosek np.limit(1)
. To o wiele gorsze niż „nieczyste” .Oto moja próba użycia tylko biblioteki Java Stream.
źródło
filter
Orzeczenie ma być bezpaństwowcem.System.out.println
jest efektem ubocznym.