2016-03-28 16 views
24

Poznaję nowe funkcje Java 8 i podczas eksperymentowania ze strumieniami (java.util.stream.Stream) i kolekcjonerami, zdałem sobie sprawę, że strumienia nie można użyć dwa razy. Czy istnieje sposób na jego ponowne wykorzystanie?Czy istnieje sposób na ponowne wykorzystanie Stream w java 8?

+0

Tak, strumienie mogą być ponownie wykorzystane, jedynie jeśli żadne z zastosowań nie wywołuje na nim żadnych operacji terminalowych. –

+0

Możliwy duplikat [Kopiuj strumień, aby uniknąć "strumień był już obsługiwany lub zamknięty" (java 8)] (http://stackoverflow.com/questions/23860533/copy-a-stream-to-avoid-stream- został już użyty-na-lub-zamknął-java-8) – Andrejs

Odpowiedz

32

Z documentation:

Strumień powinien pracować na (pośrednie lub wywoływania działania terminala Stream) tylko raz.

Implementacja strumienia może rzucić IllegalStateException, jeśli wykryje, że strumień jest ponownie wykorzystywany.

Odpowiedź brzmi: nie, strumienie nie są przeznaczone do ponownego wykorzystania.

1

Cała idea Streamu polega na tym, że jest jednorazowy. Pozwala to na tworzenie nieodnotowalnych źródeł (na przykład czytanie linii z połączenia sieciowego) bez pośredniego przechowywania. Jeśli jednak chcesz użyć ponownie zawartość Stream, można zrzucić go do kolekcji pośredniego uzyskać „wydruk”:

Stream<MyType> stream = // get the stream from somewhere 
List<MyType> list = stream.collect(Collectors.toList()); // materialize the stream contents 
list.stream().doSomething // create a new stream from the list 
list.stream().doSomethingElse // create one more stream from the list 

Jeśli nie chcesz, aby urzeczywistnić ten strumień, w niektórych przypadkach istnieje są sposoby na zrobienie kilku rzeczy jednocześnie z tym samym strumieniem. Na przykład możesz zapoznać się z this lub this, aby uzyskać szczegółowe informacje.

23

Jeśli chcesz uzyskać efekt ponownego wykorzystania strumienia, możesz zawinąć wyrażenie strumienia w dostawcy i wywołać myStreamSupplier.get(), gdy tylko chcesz nowy. Na przykład:

Supplier<Stream<String>> sup =() -> 
     someList.stream(); 
List<String> nonEmptyStrings = sup.get().filter(s -> !s.isEmpty()).collect(Collectors.toList()); 
Set<String> uniqueStrings = sup.get().collect(Collectors.toSet()); 
+1

To nie wykorzystuje ponownie strumienia. Dostawca po prostu tworzy nowy strumień, który będzie używany za każdym razem, gdy zostanie wywołany. – axiopisty

+5

Dlatego Hank D powiedział "efekt". To wciąż czystszy i bardziej wielokrotnego użytku kod. – Andrejs

9

Tak jak inni mówili: "nie, nie możesz".

Ale warto pamiętać poręczny summaryStatistics() dla wielu podstawowych operacji:

więc zamiast:

List<Person> personList = getPersons(); 

personList.stream().mapToInt(p -> p.getAge()).average().getAsDouble(); 
personList.stream().mapToInt(p -> p.getAge()).min().getAsInt(); 
personList.stream().mapToInt(p -> p.getAge()).max().getAsInt(); 

Można:

// Can also be DoubleSummaryStatistics from mapToDouble() 

IntSummaryStatistics stats = personList.stream() 
             .mapToInt(p-> p.getAge()) 
             .summaryStatistics(); 

stats.getAverage(); 
stats.getMin(); 
stats.getMax();