Wykład 2 - Kolekcje i Stream API
Java Collections Framework
Section titled “Java Collections Framework”- Kolekcje przechowują dane; w odróżnieniu od tablic nie mają stałego rozmiaru (rosną/maleją dynamicznie).
- Kolekcje nie przechowują typów prymitywnych - tylko typy referencyjne (parametryzacja generykami, np.
<Integer>). - Najczęstsze klasy:
ArrayList,Vector,LinkedList,HashSet,HashMap.
Porównanie kolekcji (kluczowa tabela)
Section titled “Porównanie kolekcji (kluczowa tabela)”| Cecha | ArrayList | Vector | LinkedList | HashSet | HashMap |
|---|---|---|---|---|---|
| Struktura | dynamiczna tablica | dynamiczna tablica | lista dwukierunkowa | tablica haszująca | tablica haszująca |
| Kolejność | wg dodania | wg dodania | wg dodania | brak gwarancji | brak gwarancji |
| Duplikaty | tak | tak | tak | nie | klucze: nie, wartości: tak |
| null | tak | tak | tak | 1× null | 1 klucz null, wiele wart. null |
| Dostęp do elem. | szybki | szybki | wolniejszy | b. szybki | b. szybki |
| Wstawianie w środku | wolne | wolne | szybkie (znany węzeł) | szybkie | szybkie |
| Synchronizacja | nie | tak | nie | nie | nie (HashTable: tak) |
| Typ | Lista | Lista | Lista/Kolejka/Deque | Zbiór (Set) | Mapa (Map) |
Fakty do zapamiętania:
ArrayList,Vector,LinkedListimplementują interfejs List; w użyciu identyczne, różnią się implementacją.ArrayListvsVector: Vector jest synchronizowany (1 wątek), ArrayList nie (wiele wątków). Przy rozszerzaniu: Vector podwaja pamięć, ArrayList +50%.LinkedList- szybsze dodawanie/usuwanie, wolniejszy dostęp (vs ArrayList/Vector odwrotnie).HashSet- szybkie sprawdzanie istnienia elementu;HashMap- szybkie wyszukiwanie wartości po kluczu.
Iterowanie
Section titled “Iterowanie”Trzy sposoby: Iterator + while(hasNext()), pętla for z iteratorem, pętla for-each (for (int x : collection)).
Stream API
Section titled “Stream API”- Dodane w Javie 8. Nie mylić ze strumieniami z pakietów Java IO.
- Stream “opakowuje” źródło danych i przetwarza je funkcyjnie; kod deklaratywny (co, nie jak).
- Umożliwia: filtrowanie, transformację, agregację oraz łatwą paralelizację.
Czym jest Stream
Section titled “Czym jest Stream”- Sekwencja elementów przetwarzanych funkcyjnie.
- Źródła: kolekcje, tablice, pliki, generatory.
- Nie przechowuje danych - operuje na źródle; nie modyfikuje źródła.
- Strumień jest jednorazowy - by użyć ponownie, trzeba go utworzyć od nowa.
Pipeline (3 elementy)
Section titled “Pipeline (3 elementy)”źródło → operacje pośrednie (transformacje) → operacja końcowa (wynik)
list.stream() .filter(x -> x.length() > 3) // pośrednia .map(String::toUpperCase) // pośrednia .sorted() // pośrednia .collect(Collectors.toList()); // końcowaTworzenie strumienia: list.stream(), Arrays.stream(arr), Stream.of("a","b"), Stream.generate(Math::random) (nieskończony).
Operacje pośrednie (zwracają nowy strumień)
Section titled “Operacje pośrednie (zwracają nowy strumień)”| Operacja | Działanie | Stateless/Stateful |
|---|---|---|
filter(Predicate) |
wybiera elementy spełniające warunek | stateless |
map(Function) |
przekształca każdy element (często zmiana typu) | stateless |
flatMap |
spłaszcza strumień strumieni (np. List<List<T>> → Stream<T>) |
stateless |
sorted() |
sortuje (natural ordering lub Comparator) |
stateful |
distinct() |
usuwa duplikaty (porównuje przez equals()) |
stateful |
limit(n) |
pierwsze n elementów | stateful |
skip(n) |
pomija pierwsze n (paginacja z limit) | stateful |
Operacje końcowe (kończą strumień)
Section titled “Operacje końcowe (kończą strumień)”| Operacja | Zwraca | Działanie |
|---|---|---|
collect(Collector) |
kolekcja/struktura | zbiera wynik (toList, toSet, toMap, groupingBy…) |
forEach(Consumer) |
nic | akcja dla każdego elementu |
count() |
long |
liczba elementów |
reduce(start, acc) |
wartość | redukcja do jednej wartości (suma, max…) |
findFirst() |
Optional<T> |
pierwszy element |
anyMatch(Predicate) |
boolean |
czy choć jeden spełnia (short-circuit) |
allMatch(Predicate) |
boolean |
czy wszystkie spełniają (short-circuit) |
Kolektory specjalne:
Collectors.groupingBy(klasyfikator)→Map<K, List<T>>(grupowanie wg klucza).Collectors.partitioningBy(predykat)→Map<Boolean, List<T>>(podział na true/false).
Stateless vs Stateful
Section titled “Stateless vs Stateful”- Stateless - element przetwarzany niezależnie, brak stanu (np.
map,filter). Bezpieczne dlaparallelStream. - Stateful - zależy od innych elementów / przechowuje stan (np.
sorted,distinct,limit). Kosztowne równolegle.
parallelStream()
Section titled “parallelStream()”- Równoległe przetwarzanie wielu wątkami, wykorzystuje ForkJoinPool (dzieli dane na zadania).
- Najlepiej dla operacji stateless i niezależnych od kolejności na dużych zbiorach.
- Nie używać dla: małych kolekcji, operacji zależnych od kolejności, efektów ubocznych/blokujących.
- Gdy ważna kolejność →
forEachOrdered()zamiastforEach().
Dobre praktyki / podsumowanie
Section titled “Dobre praktyki / podsumowanie”- Unikać efektów ubocznych, preferować dane niemutowalne, krótkie czytelne pipeline, nie nadużywać
parallelStream. - lazy evaluation (leniwa ewaluacja) poprawia wydajność.
Do zapamiętania: pipeline = źródło + operacje pośrednie + końcowa; strumień jednorazowy, nie modyfikuje źródła; znać które operacje są stateful (sorted/distinct/limit) i które pośrednie vs końcowe.