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.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:
- 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")
- Ś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.
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,x
przyrównuje jednemu elementowi kolekcji do wyliczenia (jak przyfor 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 ,forEach
co z kolei jest końcowym (końcowym) analogiem wyliczeniafor each
(wyrażenieSystem.out::println
skrótu od:,x-> System.out.println(x))
które z kolei przechodzi przez wszystkie przekazane mu elementy kolekcji i wyświetla je)
- 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 =( ;
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));
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.function
Sprawdza wartość „ true ” i „ false ”);map(Function mapper)
umożliwia utworzenie funkcji, za pomocą której zmienimy każdy element i pominiemy go dalej (interfejs funkcjonalnyFunction<T,R>
reprezentuje funkcję przejścia z obiektu typu T do obiektu typu R)flatMap(Function<T, Stream<R>> mapper)
- podobnie jak w przypadkumap
służą do konwersji na strumień pierwotny.
[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 map
konwertowania 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)
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
-
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 (supplier
dostarcza nowe obiekty (pojemniki), npnew ArrayList()
.accumulator
dodaje 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
identity
i pierwszy element strumienia, stosuje funkcjęaccumulator
iidentity
staje 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ątkowejidentity
, jest to pierwszy element strumieniaOptional 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 warunekpredicate
: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 warunkupredicate
:Stream.of(1, 2, 3, 4, 9).noneMatch(x -> x >= 7);//false
Collectors
:
-
toList()
— gromadzi elementy wList
: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ę.
GO TO FULL VERSION