JavaRush /Blog Java /Random-PL /Strumieniowe API

Strumieniowe API

Opublikowano w grupie Random-PL
API strumieniowe — 1

Co to jest API strumieniowe?

Stream API to nowy sposób pracy ze strukturami danych w funkcjonalnym stylu. Stream API (opis sposobów, w jaki jeden program komputerowy może komunikować się z innym programem) jest w swej istocie strumieniem danych. Sam termin „wątek” jest dość niejasny w programowaniu w ogóle, a w szczególności w Javie.
API strumieniowe — 1
Wraz z pojawieniem się Java 8, Stream API umożliwiło programistom pisanie znacznie krócej tego, co wcześniej zajmowało wiele linii kodu, a mianowicie uproszczenie pracy ze zbiorami danych, w szczególności uproszczenie filtrowania, sortowania i innych operacji manipulacji danymi. Jeśli nie masz operacji pośrednich, możesz i powinieneś często obejść się bez strumienia, w przeciwnym razie kod będzie bardziej skomplikowany niż bez strumienia.
Interfejs API strumieniowego — 2
Od czego dokładnie powinienem zacząć? Od stworzenia instancji Stream, która opiera się na potrzebnej nam kolekcji, tablicy lub metodzie i skąd odpowiednio będą pobierane dane:
List<String> list = new ArrayList<String>();
       list.add("One");
       list.add("Two");
       list.add("Three");
       list.add("Four");
       list.add("Five");
       list.add("Six");
       list.add("Seven");
       list.add("Eight");
       list.add("Nine");
       list.add("Ten");
       Stream stream = list.stream();
Jak wspomniano powyżej, Stream API pozwala zmniejszyć liczbę linii kodu. Przykład ze strumieniem:
IntStream.of(50, 60, 70, 80, 90, 100, 110, 120).filter(x -> x < 90).map(x -> x + 10)
.limit(3).forEach(System.out::print);
Przykład bez wątku:
int[] arr = {50, 60, 70, 80, 90, 100, 110, 120
	int count = 0;
	for (int x : arr) {
	    if (x >= 90) continue;
	    x += 10;
	    count++;
	    if (count > 3) break;
	    System.out.print(x);
	}
Możliwe sposoby utworzenia strumienia:
API strumieniowe — 3
  • Pusty strumień:Stream.empty()
  • Strumień z listy:list.stream()
  • Strumień z mapy:map.entrySet().stream()
  • Strumień z tablicy:Arrays.stream(array)
  • Strumień z określonych elementów:Stream.of("1", "2", "3")
Ponadto istnieje coś takiego jak operatory (w zasadzie metody klasy Stream).Operatory można podzielić na dwie grupy:
  • Średniozaawansowany (zwany także „leniwym”) – przetwarza przychodzące elementy i zwraca strumień. W łańcuchu przetwarzania elementów może znajdować się wiele operatorów pośrednich.
  • Terminal („terminal”, zwany także „eager”) – przetwarza elementy i kończy strumień, dzięki czemu w łańcuchu może znajdować się tylko jeden operator terminala.
Przykład:
1.List<String> list = new ArrayList<String>();
2.list.add("One");11.list.add("Ten");
12.Stream stream = list.stream();
13.stream.filter(x-> x.toString().length() == 3).forEach(System.out::println);
Co tu się dzieje:
  • 1 - utwórz listę list;
  • 2-11 - wypełnij go danymi testowymi;
  • 12 - utwórz obiekt Stream;
  • 13 - metoda filter(filtr) - operator pośredni, xprzyrównuje jednemu elementowi kolekcji do wyliczenia (jak przy for each) i po -> wskazujemy w jaki sposób nasza kolekcja jest filtrowana i ponieważ jest to operator pośredni, przefiltrowana kolekcja idzie dalej do metody , forEachco z kolei jest końcowym (końcowym) analogiem wyliczenia for each(wyrażenie System.out::printlnskrótu od:, x-> System.out.println(x))które z kolei przechodzi przez wszystkie przekazane mu elementy kolekcji i wyświetla je)
API strumieniowe — 5
Ważne punkty:
  • Przetwarzanie nie rozpocznie się, dopóki nie zostanie wywołany operator terminala. list.stream().filter(s -> s > 5)(nie pobierze ani jednego elementu z listy);
  • Instancji strumienia nie można użyć więcej niż raz =( ;
  • API strumieniowe — 6

    Dlatego za każdym razem, gdy jest nowy:

    list.stream().filter(x-> x.toString().length() == 3).forEach(System.out::println);
    list.stream().forEach(x -> System.out.println(x));
  • Na jednym strumieniu może być wywoływanych wielu operatorów pośrednich, natomiast operator terminala jest tylko jeden:

    stream.filter(x-> x.toString().length() == 3).map(x -> x + " - the length of the letters is three").forEach(x -> System.out.println(x));
Następnie przyjrzyjmy się niektórym operatorom pośrednim:
API strumieniowe — 7
  • filter(Predicate predicate)filtruje strumień, przekazując tylko te elementy, które spełniają warunek (Predicate to wbudowany interfejs funkcjonalny dodany do pakietu w Java SE 8. java.util.functionSprawdza wartość „ true ” i „ false ”);
  • map(Function mapper)umożliwia utworzenie funkcji, za pomocą której zmienimy każdy element i pominiemy go dalej (interfejs funkcjonalny Function<T,R>reprezentuje funkcję przejścia z obiektu typu T do obiektu typu R)
  • flatMap(Function<T, Stream<R>> mapper)- podobnie jak w przypadku mapsłużą do konwersji na strumień pierwotny.
Pracując na przykład z tablicą strumieni (tablice, listy itd.), konwertuje je na jeden strumień (tablicę, listę itd.) [stream1,stream2,stream3,stream4] => stream:
String[] array = {"Java", "Ruuuuussshhh"};
Stream<String> streamOfArray = Arrays.stream(array);
streamOfArray.map(s->s.split("")) //Konwertuj słowo na tablicę liter
        .flatMap(Arrays::stream).distinct() //wyrównuje każdy wygenerowany wątek do pojedynczego wątku
        .collect(Collectors.toList()).forEach(System.out::println);
Podczas mapkonwertowania na listę wątków (dokładniej <Stream>wątków) [stream1,stream2,stream3,stream4] =>Stream.of(stream1,stream2,stream3,stream4):
String[] array = {"Java", "Ruuuuussshhh"};
Stream<String> streamOfArray = Arrays.stream(array);
streamOfArray.map(s->s.split("")) //Konwertuj słowo na tablicę liter
        .map(Arrays::stream).distinct() //Uczyń tablicę osobnym wątkiem
        .collect(Collectors.toList()).forEach(System.out::println);
Kolejną różnicą w porównaniu do map, możesz przekonwertować jeden element na zero, jeden lub wiele innych. Aby zamienić jeden element na element zerowy, należy zwrócić null, czyli pusty strumień. Aby dokonać konwersji na jeden element należy zwrócić strumień z jednego elementu np. poprzez Stream.of(x). Aby zwrócić kilka elementów, możesz w dowolny sposób utworzyć strumień z tymi elementami. Ta sama metoda flatMap, ale dla Double, Integer i Long:
  • flatMapToDouble(Maper funkcji)
  • flatMapToInt (mapowanie funkcji)
  • flatMapToLong (mapowanie funkcji)
I kolejny przykład dla porównania, flatMap:
Stream.of(2, 3, 0, 1, 3)
        .flatMapToInt(x -> IntStream.range(0, x))
        .forEach(System.out::print);// 010120012
  • IntStream.range(0,x) – wyprowadza do strumienia elementy od 0 (włącznie) do x (nie włącznie);

    mapa:

    Stream.of(2, 3, 0, 1, 3)
            .map(x -> IntStream.range(0, x))
            .forEach(System.out::print);//lista strumieni (strumieni);
  • limit(long maxSize) – ogranicza strumień o ilość elementów:

    stream.limit(5).forEach(x -> System.out.println(x));
  • skip(long n) – pomija n elementów:

    stream.skip(3).forEach(x -> System.out.println(x));
  • posortowane()

  • sorted(Comparator comparator) – sortuje strumień (sortowanie jak TreeMap):

    stream.sorted().forEach(x -> System.out.println(x));
  • odrębne() — sprawdza strumień pod kątem niepowtarzalności elementów (usuwa powtórzenia elementów);

  • dropWhile(Predicate predicate) - pomija elementy spełniające warunek (pojawiło się w Javie 9, interfejs funkcjonalny Predicate<T> sprawdza, czy jakiś warunek jest spełniony. Jeśli jest spełniony, zwracana jest wartość true. Wyrażenie lambda przyjmuje obiekt typu T jako parametr:

    Predicate<Integer> isPositive = x -> x > 0;
           System.out.println(isPositive.test(3)); // true
           System.out.println(isPositive.test(-9)); // false
Operatorzy terminali:
Stream API — 8
  • forEach(Consumer action) – analogicznie do for each (Consumer<T> wykonuje jakąś akcję na obiekcie typu T, nic nie zwracając);

  • count() – zwraca liczbę elementów strumienia:

    System.out.println(stream.count());

  • Collect(Collector Collector) – metoda zbiera wszystkie elementy w listę, zbiór lub inną kolekcję, grupuje elementy według jakiegoś kryterium, łączy wszystko w ciąg znaków itp.:

    List<String> list = Stream.of(One,Two,Three).collect(Collectors.toList());
  • collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)— to samo co, collect(collector)tylko dla wygody rozkładane są parametry ( supplierdostarcza nowe obiekty (pojemniki), np new ArrayList(). accumulatordodaje element do kontenera, combinerłączy ze sobą części strumienia);

  • redukcja(T tożsamość, akumulator BinaryOperator) - konwertuje wszystkie elementy strumienia w jeden obiekt (oblicza sumę wszystkich elementów lub znajduje element minimalny), najpierw bierze obiekt identityi pierwszy element strumienia, stosuje funkcję accumulatori identitystaje się jego wynik. Następnie wszystko trwa dla pozostałych elementów.

    int sum = Stream.of(1, 2, 3, 4, 5).reduce(10, (acc, x) -> acc + x);// = 25
  • reduce(BinaryOperator accumulator)— ta sama metoda co powyżej, ale brakuje metody początkowej identity, jest to pierwszy element strumienia

    Optional min(Comparator comparator)
    Opcjonalny max(Komparator komparatora) wyszukuje element minimalny/maksymalny na podstawie przekazanego komparatora;

  • findFirst()– wyciąga pierwszy element strumienia:

    Stream.of(1, 2, 3, 4, 9).findFirst();
  • allMatch(Predicate predicate)— zwraca wartość true , jeśli wszystkie elementy strumienia spełniają warunek. Jeżeli napotkany zostanie element, dla którego wywołanie funkcji predykatu będzie miało wartość false , wówczas operator przerwie skanowanie elementów i zwróci wartość false :

    Stream.of(1, 2, 3, 4, 9).allMatch(x -> x <= 7);//false
  • anyMatch(Predicate predicate)— zwróci wartość true , jeśli przynajmniej jeden element strumienia spełnia warunek predicate:

    Stream.of(1, 2, 3, 4, 9).anyMatch(x -> x >= 7);//true
  • noneMatch(Predicate predicate)— zwróci wartość true , jeśli po przejściu przez wszystkie elementy strumienia żaden z nich nie spełnia warunku predicate:

    Stream.of(1, 2, 3, 4, 9).noneMatch(x -> x >= 7);//false
Na koniec chciałbym przyjrzeć się niektórym metodom Collectors:
  • toList()— gromadzi elementy w List:

    List<Integer> list = Stream.of(99, 2, 3).collect(Collectors.toList());
  • toSet()— zbiera elementy w zbiór:

    Set<Integer> set = Stream.of(99, 2, 3).collect(Collectors.toSet());
  • counting()— Zlicza liczbę elementów:

    Long count = Stream.of("1", "2", "3", "4").collect(Collectors.counting());
  • joining()

  • joining(CharSequence delimiter)

  • joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)— zbiera elementy w jedną linię. Dodatkowo możesz określić separator oraz przedrostek i przyrostek dla całej sekwencji:

    String a = Stream.of("s", "u" ,"p", "e", "r").collect(Collectors.joining());
           System.out.println(a); // super
    
           String b = Stream.of("s", "u", "p", "e", "r").collect(Collectors.joining("-"));
           System.out.println(b); // s-u-p-e-r
    
           String c = Stream.of("s", "u", "p", "e", "r").collect(Collectors.joining(" -> ", "[ ", " ]"));
           System.out.println(c);  // [ s -> u -> p -> e -> r ]
  • summingInt(ToIntFunction mapper)

  • summingLong(ToLongFunction mapper)

  • summingDouble(ToDoubleFunction mapper)- kolektor, który konwertuje obiekty na int/long/double i oblicza sumę.

Przydatne linki: PS: nie wstydź się zasypywać nas lajkami ^ : ^
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION