a programozás alapjai 3

21
1 A programozás alapjai 3. Java kollekció-streamek Goldschmidt Balázs [email protected] Ez az oktatási segédanyag a Budapesti Műszaki és Gazdaságtudományi Egyetem oktatója által kidolgozott szerzői mű. Kifejezett felhasználási engedély nélküli felhasználása szerzői jogi jogsértésnek minősül. Feladat: hallgatói listából válasszuk ki a 30 évnél idősebbeket és adjuk össze, hogy mennyi sört tudnak meginni! Kollekciók feldolgozása Basics of programming 3 © BME IIT, Goldschmidt Balázs 2 List<Student> l = ...; double cap = 0.0; LocalDate now = LocalDate.now(); for (Student s : l) { if (s.getBirthDate().until(now).getYears() > 30) { cap += s.getBeerCap(); } } System.out.println(cap); számítás inicializálás válogatás átalakítás 1 2

Upload: others

Post on 28-Oct-2021

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: A programozás alapjai 3

1

A programozás

alapjai 3.

Java kollekció-streamek

Goldschmidt Balázs

[email protected]

Ez az oktatási segédanyag a Budapesti Műszaki és

Gazdaságtudományi Egyetem oktatója által

kidolgozott szerzői mű. Kifejezett felhasználási

engedély nélküli felhasználása szerzői jogi

jogsértésnek minősül.

◼ Feladat:

hallgatói listából válasszuk ki a 30 évnél idősebbeket

és adjuk össze, hogy mennyi sört tudnak meginni!

Kollekciók feldolgozása

Basics of programming 3 © BME IIT, Goldschmidt Balázs 2

List<Student> l = ...;double cap = 0.0;LocalDate now = LocalDate.now();

for (Student s : l) {if (s.getBirthDate().until(now).getYears() > 30) {

cap += s.getBeerCap();}

}

System.out.println(cap);

számítás

inicializálás

válogatásátalakítás

1

2

Page 2: A programozás alapjai 3

2

◼ Mik voltak az elemi lépések?

inicializálás

◼ összegzéshez kell egy kezdő elem (0.0)

a kollekción szűrés

◼ kiválogatjuk a nekünk kellő elemeket

a kiválasztott elemek átalakítása

◼ hallgatóból sörmennyiség (Student → double, getBeerCap())

összegzés (akkumuláció)

◼ az elemek helyett közös jellemző áll elő

Bontsuk szét elemeire!

Basics of programming 3 © BME IIT, Goldschmidt Balázs 3

◼ Cél: elemek egységes kezelése

Kollekciót lehessen szűrni

◼ filter: kollekció → kollekció

Kollekció elemein lehessen egyedi leképzést csinálni

◼ map: elem → másik elem

Kumulált érték előállítása

◼ reduce: kollekció → valami más

◼ Hatékonyabb működés

párhuzamos végrehajthatóság miatt

Filter-Map-Reduce módszer

Basics of programming 3 © BME IIT, Goldschmidt Balázs 4

párhuzamosítható,

ha állapotmentes

párhuzamosítható,

ha állapotmentes

párhuzamosítható,

ha asszociatív

3

4

Page 3: A programozás alapjai 3

3

◼ Feladat:

hallgatói listából válasszuk ki a 30 évnél idősebbeket

és adjuk össze, hogy mennyi sört tudnak meginni!

Stream alapjai

Basics of programming 3 © BME IIT, Goldschmidt Balázs 5

List<Student> l = ...;LocalDate now = LocalDate.now();

double cap = l.stream().filter(s->(s.getBirthDate().until(now)

.getYears() > 30)).map(Student::getBeerCap).reduce(0.0, Double::sum)

;System.out.println(cap);

forrás

átalakítás

összegzés

válogatás

◼ Adatszerkezet: stream

objektumfolyam

◼ lehet DoubleStream, IntStream, LongStream is

lehet párhuzamos vagy sorrendi

◼ parallel vs. sequential

◼ a feldolgozás végezhető-e párhuzamosan

a tartalma jöhet bárhonnan

◼ kollekció, hálózat, más stream-ek, …

◼ Feldolgozás: pipeline (forrás) – (köztes művelet)* – (záró művelet)

(source) – (intermediate op)* – (terminal op)

Stream alapfogalmak

Basics of programming 3 © BME IIT, Goldschmidt Balázs 6

lusta

kiértékelés

5

6

Page 4: A programozás alapjai 3

4

◼ Tömeges feldolgozás

kollekcióra és végtelen forrásra egyaránt

◼ De: a hagyományos kollekció egyedi hozzáférésre jobb!

◼ Hatékonyság

könnyen párhuzamosítható

◼ állapotmentes (stateless) műveletek előnyben

◼ asszociatív összegzések (redukciók) előnyben

jól definiált elemi műveletek

◼ minden elemre egységesen

◼ olvasható, karbantartható

Stream előnyei

Basics of programming 3 © BME IIT, Goldschmidt Balázs 7

◼ Pipeline feldolgozás

(forrás) – (köztes művelet)* – (záró művelet)

◼ pl. l.stream().filter(x).map(y).reduce(z);

Forrás

◼ kollekcióból, hálózatról, generátorral stb.

Köztes: szűrések/leképezések (filter/map)

◼ tetszőleges számú

◼ közös be-kimenő típusaik kompatibilisek legyenek

◼ lusta kiértékelés

Záró: redukció

◼ lezárja a streamet

◼ a stream nem használható újra

Stream használata

Basics of programming 3 © BME IIT, Goldschmidt Balázs 8

7

8

Page 5: A programozás alapjai 3

5

Stream-pipeline

Basics of programming 3 © BME IIT, Goldschmidt Balázs 9

M1 M2 M3F1S1 S2 S3 S4 S5 RForrás

Stream létrehozása

Basics of programming 3 © BME IIT, Goldschmidt Balázs 10

M1 M2 M3F1Forrás S1 S2 S3 S4 S5 R

9

10

Page 6: A programozás alapjai 3

6

◼ Collection<T>-ből stream()

◼ szekvenciális feldolgozású

parallelStream()

◼ párhuzamos feldolgozású

◼ Tömbből Arrays.stream(T[] t, int startIncl, int endExcl)

int, long, double típusra is

Stream létező elemekből

Basics of programming 3 © BME IIT, Goldschmidt Balázs 11

Stream<String> s = Arrays.stream(args);

◼ Stream<T> statikus metódusaival empty()

◼ üres stream

concat(Stream<? ext T> a, Stream<? ext T> b)

◼ meglevő két streamet összefűz

of(T t)

of(T... values)

◼ egy/több T-ből stream

Stream létező elemekből

Basics of programming 3 © BME IIT, Goldschmidt Balázs 12

Stream<String> s = Stream.of("hello", "world");

11

12

Page 7: A programozás alapjai 3

7

◼ Stream<T> statikus metódusaival generate(Supplier<T> s)

◼ visszatér egy s által biztosított tartalmú streammel

◼ T s.get() metódust hívva

◼ végtelen hosszú

Stream generálása

Basics of programming 3 © BME IIT, Goldschmidt Balázs 13

// kockadobások végtelen sorbanRandom rnd = new Random();Stream<Integer> s = Stream.generate(()->(rnd.nextInt(6)+1));

◼ Stream<T> statikus metódusaival iterate(T seed, Predicate<? super T> hasNext,

UnaryOperator<T> f))

◼ seed kezdőértékkel

◼ opcionális hasNext-ig,

◼ f függvény ismételt meghívása

◼ elemei: seed, f(seed), f(f(seed)), f(f(f(seed))), …

Stream generálása

Basics of programming 3 © BME IIT, Goldschmidt Balázs 14

// 2 hatványai: 1, 2*1=>2, 2*2=>4, 2*4=>8, ...Stream<Integer> s = Stream.iterate(1, x->2*x);

13

14

Page 8: A programozás alapjai 3

8

Stream köztes műveletei

Basics of programming 3 © BME IIT, Goldschmidt Balázs 15

M1 M2 M3F1Forrás S1 S2 S3 S4 S5 R

Stream<T>-n, az eredmény is Stream<T>

◼ állapotmentes (stateless) műveletek

filter(Predicate<? super T> predicate)

◼ a predikátumnak megfelelő elemek maradnak meg

◼ példa: számoljuk meg a 3,5 átlagnál jobbakat

Szűrő metódusok (köztes)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 16

long cnt = l.parallelStream().filter(s-> (s.getAverage()>3.5)).count();

Student → boolean

15

16

Page 9: A programozás alapjai 3

9

Stream<T>-n, az eredmény is Stream<T>

◼ állapottal rendelkező (stateful) műveletek

sorted([Comparator<? super T> comparator])

◼ elemek rendezve

◼ példa: írjuk ki fordított átlag (azon belül névsor) szerint

Szűrő metódusok (köztes)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 17

l.stream().sorted(Comparator.comparing(Student::getAverage)

.reversed()

.thenComparing(Student::getName)).forEach(System.out::println);

Kaszkád

komparátor

Stream<T>-n, az eredmény is Stream<T>

◼ állapottal rendelkező (stateful) műveletek

distinct()

◼ ismétlődések elhagyása (equals alapján)

limit(long maxSize)

◼ legfeljebb maxSize-nyi elem megtartása

skip(long n)

◼ az első n elem eldobása

Szűrő metódusok (köztes)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 18

17

18

Page 10: A programozás alapjai 3

10

Stream<T>-n, az eredmény Stream<R>

◼ a leképzés egy T-ből egy R-t csinál

◼ állapotmentes (stateless) műveletek

map(Function<? super T, ? extends R> mapper)

◼ a mapper-nek megfelelő leképzés

◼ egy-egyes leképezésekre (pl. ember és a sörkapacitása)

mapToInt(ToIntFunction<? super T> mapper)

◼ a mapper T-ből int-et csinál, visszatérés IntStream

IntStream dedikált stream int típusra

◼ fentiek long és double típusra is

Leképző metódusok (köztes)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 19

Példa: sörkapacitás logaritmusát összegezzük

Leképző metódusok (köztes)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 20

double cap = l.parallelStream().map(s->Math.log(s.getBeerCap())).reduce(0.0, Double::sum)

;

Student → double

double cap = l.parallelStream().mapToDouble(s->Math.log(s.getBeerCap())).sum()

;DoubleStream metódusa

19

20

Page 11: A programozás alapjai 3

11

Stream<T>-n, az eredmény Stream<R>

◼ a leképezés egy-több típusú (T → Stream<R>)

◼ állapotmentes (stateless) műveletek

flatMap(Function<? super T,? extends Stream<? extends R>> mapper)

◼ flatMap egyesíti az eredmény-streameket

◼ van flatMapToInt, flatMapToLong és flatMapToDouble is

eredmény IntStream, LongStream illetve DoubleStream

Leképző metódusok (köztes)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 21

List<String> lines = ...;long words = lines.parallelStream().flatMap(s->Arrays.stream(s.split(" "))).count();

sorokból szavak

Stream redukciója

Basics of programming 3 © BME IIT, Goldschmidt Balázs 22

M1 M2 M3F1Forrás S1 S2 S3 S4 S5 R

21

22

Page 12: A programozás alapjai 3

12

T reduce(T identity, BinaryOperator<T> acc)

◼ összegzés identity kezdőértékkel

◼ acc összegez (accumulator)

◼ elvi működés:

Redukáló metódusok (záró)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 23

T result = identity;for (T element : this_stream)

result = acc.apply(result, element);return result;

double cap = l.stream().map(Student::getBeerCap).reduce(0.0, Double::sum);

Optional<T> reduce(BinaryOperator<T> acc))

◼ összegzés null kezdőértékkel

◼ acc összegez

◼ Optional<T> vagy üres, vagy az eredmény van benne

eredmény: T get() metódussal lekérhető; kivételt dob, ha nincs

van-e eredmény: boolean isPresent()

Redukáló metódusok (záró)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 24

Optional<Double> cap = l.stream().map(Student::getBeerCap).reduce(Double::sum);

double c = cap.get();

23

24

Page 13: A programozás alapjai 3

13

néha egyszerűbb összevonni a szűrést és az

összegzést

Összetett reduce (záró)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 25

double cap = l.stream().map(s->Math.log(s.getBeerCap())).reduce(0.0, Double::sum)

;

double cap = l.stream().reduce(0.0,

(sum, s)->sum+Math.log(s.getBeerCap()),Double::sum)

;

Részeredmény

számítása

Részeredmények

kombinálása

Studentek

Student → double

double-k összeadása

void forEach(Consumer<? super T> action))

void forEachOrdered(Consumer<? super T> action))

◼ végrehajtja action-t minden elemen

◼ az ordered determinisztikusan, sorrendben

◼ elvi működés:

Feldolgozó metódusok (záró)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 26

for (T element : this_stream)action.apply(element);

l.stream().forEach(System.out::println);

25

26

Page 14: A programozás alapjai 3

14

Optional<T> max(Comparator<? super T> comparator)

Optional<T> min(Comparator<? super T> comparator)

◼ max/min érték keresése

◼ Optional<T> vagy üres, vagy az eredmény van benne

eredmény: T get() metódussal elérhető

van-e eredmény: boolean isPresent()

Redukáló metódusok (záró)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 27

Optional<Double> cap = l.stream().map(Student::getBeerCap).max(Double::compare);

double c = cap.get(); általános

megoldás

boolean allMatch(Predicate<? super T> predicate)

boolean anyMatch(Predicate<? super T> predicate)

boolean noneMatch(Predicate<? super T> predicate)

◼ a feltételnek megfelel-e mindegyik, legalább egy, egy sem

long count()

◼ az elemek száma

IntStream, LongStream, DoubleStream esetén

average(), max(), min()

◼ átlag, maximum, minimum

Redukáló metódusok (záró)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 28

OptionalDouble cap = l.stream().mapToDouble(Student::getBeerCap).max();

27

28

Page 15: A programozás alapjai 3

15

Pipeline belső állapota

Basics of programming 3 © BME IIT, Goldschmidt Balázs 29

M1 M2 M3F1Forrás S1 S2 S3 S4 S5 R

Stream<T> peek(Consumer<? super T> action)

◼ minden elemen lefut az action

◼ nem módosítja a streamet

◼ alapvetően debug célból

Pipeline belső állapota (köztes)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 30

double cap = l.stream().filter(s->(s.getBirthDate().until(now)

.getYears() > 30)).peek(System.out::println).map(Student::getBeerCap).reduce(0.0, Double::sum)

;

29

30

Page 16: A programozás alapjai 3

16

Streamből Collection

Basics of programming 3 © BME IIT, Goldschmidt Balázs 31

M1 M2 M3F1Forrás S1 S2 S3 S4 S5 R Cél

◼ Feladat

meglevő stream-ből a 30 évnél idősebb hallgatók

listáját kinyerni

Streamből Collection

Basics of programming 3 © BME IIT, Goldschmidt Balázs 32

List<Student> l = ...;LocalDate now = LocalDate.now();

List<Student> l30 = l.stream().filter(s->(s.getBirthDate().until(now)

.getYears() > 30)).collect(Collectors.toList());

31

32

Page 17: A programozás alapjai 3

17

◼ Kigyűjtés R collect(Collector<? super T, A, R> collector)

◼ a collector segítségével R (egy kollekció) előállítása

◼ Collector intefészben több metódus

T: a stream-beli elemek típusa

A: átmeneti tároló típusa

◼ általában nem ismerjük, ?-lel jelölik

◼ pl. stringek összefűzésekor A nem String, mert drága lenne

R: a visszaadott kollekció típusa

Streamből Collection (záró)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 33

◼ Collectors segédosztály (utility class) Collector<T,?,List<T>> toList()

Collector<T,?,Set<T>> toSet()

Collector<T,?,C> toCollection(Supplier<C> cFac)

◼ lista, halmaz vagy más kollekció generálása

◼ cFac legyárt egy C típusú kollekciót

ahol C extends Collection<T>

Streamből Collection (záró)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 34

List<Student> l2 = l.stream().filter(s->(s.getBirthDate().until(now)

.getYears() > 30)).collect(Collectors.toList());

33

34

Page 18: A programozás alapjai 3

18

◼ Collectors segédosztály (utility class) Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper,

Function<? super T,? extends U> valueMapper)

◼ Map létrehozása és feltöltése

◼ példa: nevekhez sörkapacitás Map-ben

Streamből Map (záró)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 35

Map<String,Double> bm1 = l.stream().collect(Collectors.toMap(Student::getName,

Student::getBeerCap));

Map<String,Double> bm2 = l.stream().collect(Collectors.toMap(Student::getName,

s->Math.log(s.getBeerCap())));

◼ Collectors segédosztály (utility class) Collector<T,?,Map<K,List<T>>>groupingBy(Function<? sup T,? ext K> classifier)

◼ Map létrehozása és feltöltése

◼ példa: sörkapacitásokhoz hallgatók Map-ben

Streamből Map (záró)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 36

Map<Double,List<Student>> bs = l.stream().collect(Collectors

.groupingBy(Student::getBeerCap));

35

36

Page 19: A programozás alapjai 3

19

◼ Collectors segédosztály (utility class) Collector<T,?,Map<K,D>>groupingBy(Function<? sup T,? ext K> classifier,

Collector<? super T,A,D> subcollect)

◼ Map létrehozása és feltöltése

◼ az egyes kulcsokhoz tartozó elemek külön-külön kollektálásával

◼ példa: születési év alapján átlagos sörkapacitás Map-ben

Streamből Map (záró)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 37

Map<Integer,Double> yavg = l.stream().collect(Collectors

.groupingBy(s->s.getBirthDate().getYear(),Collectors.averagingDouble(Student::getBeerCap)

));

◼ Collectors segédosztály (utility class) Collector<CharSequence,?,String>joining([CharSequence delimiter, [CharSequence prefix, CharSequence suffix]]))

◼ String létrehozása a stream tartalmából összefűzéssel

◼ példa: nevek összefűzése újsorjellel

Streamből String (záró)

Basics of programming 3 © BME IIT, Goldschmidt Balázs 38

String names = l.stream().map(Student::getName()).collect(Collectors.joining("\n"));

37

38

Page 20: A programozás alapjai 3

20

◼ Feladat:

hallgatói listából válasszuk ki a 30 évnél idősebbeket

átlagosan mennyi sört tudnak meginni?

Számoljunk átlagot!

Basics of programming 3 © BME IIT, Goldschmidt Balázs 39

List<Student> l = ...;LocalDate now = LocalDate.now();

double avg = l.stream().filter(s->(s.getBirthDate().until(now)

.getYears() > 30)) .collect(Collectors

.averagingDouble(Student::getBeerCap));

System.out.println(avg); Collector-ral

◼ Feladat:

hallgatói listából válasszuk ki a 30 évnél idősebbeket

átlagosan mennyi sört tudnak meginni?

Számoljunk átlagot!

Basics of programming 3 © BME IIT, Goldschmidt Balázs 40

List<Student> l = ...;LocalDate now = LocalDate.now();

OptionalDouble avg = l.stream().filter(s->(s.getBirthDate().until(now)

.getYears() > 30)) .mapToDouble(Student::getBeerCap).average();

System.out.println(avg);DoubleStream-mel

39

40

Page 21: A programozás alapjai 3

21

◼ Soros vagy párhuzamos és egyebek boolean isParallel()

◼ megadja, hogy párhuzamosan dolgozzuk-e fel

Stream<T> parallel()

Stream<T> sequential()

◼ visszaad egy azonos tartalmú streamet,

ami párhuzamos/soros feldolgozású

Stream<T> unordered()

◼ visszaad egy azonos tartalmú streamet,

ami rendezetlen

Iterator<T> iterator()

◼ iterátor a stream elemein

Stream jellege

Basics of programming 3 © BME IIT, Goldschmidt Balázs 41

Basics of programming 3 © BME IIT, Goldschmidt Balázs 42

Köszönöm a figyelmet!

41

42