Java. Pytania rekrutacyjne dla Juniora: Rodzaje operacji w streamach (strumieniach).

Streamy w Javie wprowadzano w wersji 8 i znacznie ułatwiły przeprowadzanie wielu operacji na kolekcjach, często zastępując mniej czytelne pętle. I choć idea strumieni jest w miarę jasna warto przed rozmową kwalifikacyjną przypomnieć sobie trochę szczegółów o budowie i rodzajach operacji na streamach.

Dwa rodzaje operacji na streamach – pośrednie i końcowe.

Struktura strumienia, czy też jego rurociąg (ang. pipeline), składa się z trzech elementów:

  • źródła (np. kolekcji) przekształconego w strumień;
  • od zera do wielu operacji pośrednich (ang. intermediate operations);
  • zera lub jednej operacji końcowej (lub też terminalnej, ang. terminal operation) zwracającej wynik.

Operacje pośrednie odpowiadają za przekształcenie strumienia, a należą do nich takie metody jak filter(Predicate), map(Function). flatMap(Function) czy distinct().  Ich pełna lista znajduje się w dokumentacji, do której link zamieszczam na dole wpisu. Odróżnicie je łatwo, gdyż metody pośrednie zwracają obiekty typu Stream. 

Operacje końcowe natomiast odpowiadają za zwrócenie konkretnego rezultatu. Zwracają więc typ prosty lub obiekt jak np. count() zwraca wartość typu long, a findAny() zwróci nam Optional.

Być może zastanowiło was dlaczego operacji może być zero, zarówno pośrednich jak i końcowej. Chociaż w niektórych komentarzach można znaleźć informację, że strumień składa się z przynajmniej jednej metody pośredniej przed wykonaniem operacji końcowej, to nie ma takiej potrzeby.

Możemy użyć przecież takiego strumienia, jak poniżej. Chociaż praktycznie nie ma on żadnego uzasadnienia i powinien być zastąpiony wywołaniem metody size() na danej kolekcji. 

List<Integer> ints = IntStream.iterate(0, x -> x + 1)
       .limit(100)
       .boxed()
       .collect(Collectors.toList());

long count = ints.stream().count();
long count2 = ints.size();

Również użycie metody końcowej nie jest konieczne, gdyż zwracanym obiektem może być po prostu Stream. Wyobraźmy sobie podział strumienia na dwie części, wówczas uzyskamy jeden strumień bez operacji końcowej, drugi bez operacji pośredniej. Jak poniżej:

Stream<Integer> intStream = IntStream.iterate(0, x -> x + 1)
                .limit(100)
                .boxed(); // boxed() is an intermediate operation
long countIntStream = intStream.count(); // count() is a terminal operation

Pytanie (?). Czy w takim przypadku możemy wykonać dwie operacje końcowe? Na przykład:

Stream<Integer> intStream = IntStream.iterate(0, x -> x + 1)
                .limit(100)
                .boxed(); 
long countIntStream = intStream.count(); 
Optional<Integer> findFirstIntStream = intStream.findFirst(); //Exception?

Odpowiedź znajdziecie w kolejnym wpisie.

Streamy wyspecjalizowane dla typów prostych i ich metody

Inną wartą wspomnienia kwestią są odpowiednie specjalizacje dla typów prostych:

  • IntStream
  • DoubleStream 
  • LongStream

Mają one swoje metody pośrednie jak np. boxed() odpowiadająca za opakowanie typów prostych w obiekty, czyli z angielskiego boxing. Możecie się z nimi spotkać na przykład używając metod mapToInt(Predicate) czy mapToLong(Predicate). Zwracają one odpowiednio IntStream i LongStream. Pamiętajcie jednak, że zanim użyjemy metody końcowej wymagającej obiektów, a nie typów prostych należy użyć właśnie metody boxed().

Dokładny opis streamów znajdziecie w dokumentacji pod linkiem: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html

Jeżeli macie uwagi bądź pytania, piszcie w komentarzach.

PS. Staram się używać zamiennie polskich i oryginalnych nazw. W programowaniu angielski jest podstawowym językiem i często w ogóle nie używa się polskich określeń. Czasem polskie nazwy potrafią wręcz wprawić w zakłopotanie, jednak spotykam się z nimi w literaturze czy na innych blogach, więc taka zamienność nazw mam nadzieję, że będzie jedynie pomocna dla osób zaczynających programować.

Java. Pytania rekrutacyjne dla Juniora: Rodzaje operacji w streamach (strumieniach).

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Przewiń do góry