W Javie 8 mamy klasę Stream <T> , która, co ciekawe, ma metodę
Iterator<T> iterator()
Można się więc spodziewać, że zaimplementuje interfejs Iterable <T> , który wymaga dokładnie tej metody, ale tak nie jest.
Kiedy chcę iterować po strumieniu za pomocą pętli foreach, muszę zrobić coś takiego
public static Iterable<T> getIterable(Stream<T> s) {
return new Iterable<T> {
@Override
public Iterator<T> iterator() {
return s.iterator();
}
};
}
for (T element : getIterable(s)) { ... }
Czy coś mi umyka?
java
java-8
java-stream
iterable
roim
źródło
źródło
Stream
do starszych interfejsów API, które oczekująIterable
getIterable()
doreturn s::iterator;
for (T element : stream::iterator)
, więc nadal wolałbym, aby Stream również zaimplementowałbyIterable
lub metodętoIterable()
.Odpowiedzi:
Ludzie pytali już o to samo na liście mailingowej ☺. Głównym powodem jest to, że Iterable ma również powtarzalną semantię, podczas gdy Stream nie.
źródło
Iterable
dotyczącej tego, czyiterator
należy zawsze, czy nie, można wywoływać wielokrotnie. To coś, co powinni tam umieścić. Wydaje się, że jest to bardziej standardowa praktyka niż formalna specyfikacja.Aby przekonwertować
Stream
na aIterable
, możesz to zrobićAby przekazać
Stream
metodę, która oczekujeIterable
:po prostu
jednak prawdopodobnie wygląda śmiesznie; może lepiej być trochę bardziej wyraźnym
źródło
for(X x : (Iterable<X>)stream::iterator)
, choć wygląda brzydko. Naprawdę cała ta sytuacja jest po prostu absurdalna.IntStream.range(0,N).forEach(System.out::println)
stream::iterator
astream.iterator()
tym samym sprawia, że pierwsze jest akceptowalne dlaIterable
drugiego, ale nie drugie?Iterable
to interfejs funkcjonalny, więc wystarczy przekazać funkcję, która go implementuje.Chciałbym zauważyć, że
StreamEx
implementujeIterable
(iStream
), a także wiele innych niesamowicie niesamowitych funkcji, których brakujeStream
.źródło
Możesz użyć strumienia w
for
pętli w następujący sposób:(Uruchom ten fragment tutaj )
(Używa to obsady interfejsu Java 8).
(Jest to opisane w niektórych powyższych komentarzach (np. Aleksandr Dubinsky ), ale chciałem wyciągnąć je w odpowiedzi, aby było bardziej widoczne.)
źródło
kennytm opisał, dlaczego niebezpieczne jest traktowanie
Stream
jako „a”Iterable
, a Zhong Yu zaproponował obejście, które pozwala na użycie „takStream
jak”Iterable
, choć w niebezpieczny sposób. Jest to możliwe, aby uzyskać najlepsze z obu światów: wielokrotnego użytkuIterable
z punktu AStream
, który spełnia wszelkie gwarancje dokonane przezIterable
specyfikację.Uwaga:
SomeType
nie jest tutaj parametrem typu - należy go zastąpić odpowiednim typem (np.String
) Lub zastosować odbicieJest jedna poważna wada:
Korzyści z leniwej iteracji zostaną utracone. Jeśli planujesz natychmiastowe iterowanie wszystkich wartości w bieżącym wątku, wszelkie koszty ogólne będą nieistotne. Jeśli jednak planujesz iterować tylko częściowo lub w innym wątku, ta natychmiastowa i pełna iteracja może mieć niezamierzone konsekwencje.
Dużą zaletą jest oczywiście to, że można ponownie użyć
Iterable
, podczas gdy(Iterable<SomeType>) stream::iterator
zezwala się tylko na jedno użycie. Jeśli kod odbierający będzie wielokrotnie iterował kolekcję, jest to nie tylko konieczne, ale prawdopodobnie korzystne dla wydajności.źródło
Stream.toArray()
zwraca tablicę, a nie anIterable
, więc ten kod nadal się nie kompiluje. ale może to być błąd w zaćmieniu, ponieważ IntelliJ wydaje się to kompilowaćStream
nie implementujeIterable
. Ogólne zrozumienieIterable
jest wszystkim, co można powtarzać, często od nowa.Stream
mogą nie być odtwarzane.Jedynym sposobem, w jaki mogę wymyślić, gdzie można odtworzyć iterację opartą na strumieniu, jest odtworzenie strumienia. Używam
Supplier
poniżej, aby utworzyć nową instancję strumienia, za każdym razem, gdy tworzony jest nowy iterator.źródło
Jeśli nie przeszkadza przy użyciu bibliotek stron trzecich cyklop reagują definiuje Stream, który implementuje zarówno Stream i iterable i replayable zbyt (rozwiązując problem kennytm opisane ).
lub:
[Ujawnienie Jestem wiodącym twórcą Cyclops-reag]
źródło
Nie idealnie, ale zadziała:
Nie idealne, ponieważ będzie pobrać wszystkie elementy ze strumienia i umieścić je w to
List
, co nie jest dokładnie to, coIterable
iStream
chodzi. Powinny być leniwi .źródło
Możesz iterować wszystkie pliki w folderze, korzystając z
Stream<Path>
tego:źródło