Sunteți pe pagina 1din 26

1

Prezentare 18:
Streams –
colectarea
datelor
PROGRAMARE ORIENTATA
OBIECT
2020
Streams – colectare date

 Exemplu – gruparea unei liste de tranzactii pe baza tipului de valuta


utilizata
Java < 8
Map<Valuta, List<Tranzactie>> grupTranzValuta = new HashMap<>();

for (Tranzactie tranz: tranzactii) {


Valuta val = tranz.getValuta();
List<Tranzactie> tranzTipValuta = grupTranzValuta.get(val);
if (tranzTipValuta == null) {
tranzTipValuta = new ArrayList<>();
grupTranzValuta.put(val, tranzTipValuta);
}
tranzTipValuta.add(tranz);
}
24.01.2021 POO 2
Streams – colectare date

Java >=8

Map<Valuta, List<Tranzactie>> grupTranzValuta =


tranzactii.stream().collect(groupingBy(Tranzactie::getValuta));

24.01.2021 POO 3
Streams – colectare date

 Collectors – permit definirea criteriilor pe baza carora collect creeaza


colectia dorita
procesul de
Collector reducere
stream rezultat

Functie de
transformare

extrage valuta
traverseaza
tranzactiei adauga perechea
fiecare tranzactie
din stream valuta/tranzactie la map

24.01.2021 POO 4
Streams – colectare date

 Metodele clasei Collectors - permit:


 reducerea si sumarizarea elementelor stream-ului la o singura valoare

 gruparea elementelor

 partitionarea elementelor

24.01.2021 POO 5
Streams – colectare date

 Reducere si sumarizare
Exemplu – numarul felurilor din meniu utilizand colectorul intors de
metoda counting
long numarFeluri = meniu.stream().collect(Collectors.counting());

Poate fi scris si:


long numarFeluri = meniu.stream().count();

Prima solutie permite compunerea colectorilor

25.01.2021 POO 6
Streams – colectare date

 Minimul si maximul dintr-un stream de valori – Collectors.maxBy,


Collectors.minBy
Exemplu – felul cu cele mai multe calorii

Comparator<Fel> compCalorii =
Comparator.comparingInt(Fel::getCalorii);

Optional<Fel> felMaxCalorii =
meniu.stream()
.collect(maxBy(compCalorii));

24.01.2021 POO 7
Streams – colectare date

 Sumarizare – Collectors.summingInt, Collectors.summingDouble,


Collectors.summingLong
Exemplu – numarul total de calorii din meniu
int numarTotalCalorii = meniu.stream().collect(summingInt(Fel::getCalorii));

 Calcul medie – Collectors.averagingInt, Collectors.averagingDouble,


Collectors.averagingLong
Exemplu – numarul mediu de calorii din meniu
double numarMediuCalorii =
meniu.stream().collect(averagingInt(Fel::getCalorii));

24.01.2021 POO 8
Streams – colectare date

 Statistici – Collectors.summarizingInt
Exemplu – suma, media, min, max caloriilor din meniu
IntSummaryStatistics statisticiMeniu =
meniu.stream().collect(summarizingInt(Fel::getCalorii));

 Concatenare siruri – Collectors.joining


Exemplu – concatenarea numelor felurilor din meniu
String meniuScurt =
meniu.stream().map(Fel::getNume).collect(joining());
String meniuScurt =
meniu.stream().map(Fel::getNume).collect(joining(“, “));
24.01.2021 POO 9
Streams – colectare date

 Sumarizare generalizata cu reducere – Collectors.reducing


Exemplu – numarul total de calorii din meniu

int numarTotalCalorii = meniu.stream().collect(reducing(


0, Fel::getCalorii, (i, j) -> i + j));
int numarTotalCalorii = meniu.stream().collect(reducing(0,
Fel::getCalorii,
Integer::sum));
Exemplu – felul cu cele mai multe calorii

Optional<Fel> felCaloric = meniu.stream().collect(reducing(


(f1, f2) -> f1.getCalorii() > f2.getCalorii()? f1 : f2));

24.01.2021 POO 10
Streams – colectare date

 reduce vs collect

Stream<Integer> stream = Arrays.asList(1,2,3,4,5,).stream();


List<Integer> numere = stream.reduce(
new ArrayList<Integer>();
(List<Integer> l, Integer e) -> {
l.add(e);
return l; },
(List<Integer> l1, List<Integer> l2 -> {
l1.addAll(l2);
return l1;});

25.01.2021 POO 11
Streams – colectare date

 Grupare – Collectors.groupingBy
Exemplu – clasificarea felurilor din meniu pe baza tipului lor (carne,
peste, altele)
Map<Fel.Tip, List<Fel>> claseFeluri =
meniu.stream().collect(groupingBy(Fel::getTip));
Exemplu – clasificarea felurilor din meniu pe baza numarului de calorii
public enum NivelCalorii {DIET, NORMAL, GRAS}
Map<NivelCalorii, List<Fel>> felNivelCaloric = meniu.stream().collect(
groupingBy(fel -> {
if (fel.getCalorii() <= 400) return NivelCalorii.DIET;
else if (fel.getCalorii() <= 700) return NivelCalorii.NORMAL;
else return NivelCalorii.GRAS;
24.01.2021
})); POO 12
Streams – colectare date

 Prelucrarea elementelor din grupuri


Exemplu – filtrarea elementelor calorice (> 500 calorii)

Map<Fel.Tip, List<Fel>> feluriCaloriceTip = meniu.stream() categoria PESTE nu


.filter(fel -> fel.getCalorii() > 500) va aparea daca are
.collect(groupingBy(Fel::getTip)); 0 elemente

Map<Fel.Tip, List<Fel>> feluriCaloriceTip =


meniu.stream().collect(groupingBy(Fel::getTip),
filtering(fel -> fel.getCalorii() > 500, toList()));

25.01.2021 POO 13
Streams – colectare date

 Prelucrarea elementelor din grupuri


Exemplu – conversia fiecarui fel din grupuri la numele lui

Map<Fel.tip, List<String>> numeFeluriTip =


meniu.stream().collect(groupingBy(Fel::getTip),
mapping(Fel::getNume(), toList()));

25.01.2021 POO 14
Streams – colectare date

 Grupare pe mai multe nivele


Exemplu – filtrarea elementelor calorice (> 500 calorii)

Map<Fel.tip, Map<NivelCaloric, List<Fel>>> feluriCaloriceTipNivel =


meniu.stream().collect(
groupingBy(Fel::getTip,
groupingBy(fel -> {
if (fel.getCalorii() <= 400) return NivelCaloric.DIET;
else if (fel.getCalorii() <= 700) return NivelCaloric.NORMAL;
else return NivelCaloric.GRAS;
})
)
);

24.01.2021 POO 15
Streams – colectare date

 Colectarea datelor in subgrupuri


Exemplu – numarul de feluri din meniu pentru fiecare tip

Map<Fel.Tip, Long>> numarTip = meniu.stream().collect(


groupingBy(Fel::getTip, counting()));

24.01.2021 POO 16
Streams – colectare date

 Partitionare – grupare pe baza de predicat


Exemplu – partitionarea meniului in vegetarian si nevegetarian

Map<Boolean, List<Fel>> meniuPartitionat = meniu.stream().collect(


partitioningBy(Fel::eVegetarian));

Regasirea felurilor vegetariene:

List<Fel> feluriVegetariene = meniuPartitionat.get(true);

24.01.2021 POO 17
Streams – colectare date

Exemplu – crearea unei partitionari pe nivele


Map<Boolean, Map<Fel.Tip, List<Fel>>> feluriCaloriceTip =
meniu.stream().collect(partitioningBy(Fel::eVegetarian,
groupingBy(fel::getTip));

Exemplu – partitionarea numerelor in prime si neprime


public boolean ePrim(int cand) {
int radCand = (int) Math.sqrt((double)cand);
return IntStream.rangeClosed(2, radCand)
.noneMatch(i -> cand % i == 0);

24.01.2021 POO 18
Streams – colectare date

public Map<boolean, List<Integer>> partPrim(int n) {


return IntStream.rangeClosed(2, n).boxed()
.collect(
partitioningBy(cand -> ePrim(cand)));

24.01.2021 POO 19
Streams – colectare date

 Interfata Collector

public interface Collector<T, A, R> {


Supplier<A> supplier();
BiConsumer<A, T> accumulator();
Function<A, R> finisher();
BinaryOperator<A> combiner();
Set<Characteristics> characteristics();

o T – tipul generic al elementelor stream-ului de colectat


o A – tipul acumulatorului
o R – tipul obiectului rezultat in urma operatiei de colectare

25.01.2021 POO 20
Streams – colectare date

 Metoda supplier
public Supplier<List<T>> supplier() {
return () -> new ArrayList<T>();
}

Se poate transfera si o referinta la un constructor:

public Supplier<List<T>> supplier() {


return ArrayList::new;
}

25.01.2021 POO 21
Streams – colectare date

 Metoda accumulator
public BiConsumer<List<T>, T> accumulator() {
return (list, elem) -> list.add(elem);
}

Utilizand o referinta la metoda:

public BiConsumer<List<T>, T> accumulator() {


return List::add;
}

25.01.2021 POO 22
Streams – colectare date

 Metoda finisher
public Function<List<T>, List<T>> finisher() {
return Function.identity();
}

 Metoda combiner

public BinaryOperator<List<T>> combiner() {


return (list1, list2) ->
list1.addAll(list2);
return list;
}

25.01.2021 POO 23
Streams – colectare date

 Metoda characteristics – intoarce o multime imutabila de elemente de


tip Characteristics care definesc comportamentul unui colector

 Characteristics - enumerare care continue elementele:


 UNORDERED – rezultatul reducerii nu este afectat de ordinea
parcurgerii si a acumularii elementelor stream-ului
 CONCURRENT – metoda accumulator paote fi apelata concurrent
 IDENTITY_FINISH – metoda intoarsa de finisher este cea identitate

25.01.2021 POO 24
Streams – colectare date

import java.util.*;
import java.util.function.*;
import java.stream.Collector;
import java.stream.Collector.Characteristics.*;

public class ToListCollector<T> implements Collector<T, List<T>, List<T>> {


{
@override
public Supplier<List<T>> supplier() {
return ArrayList::new;
}
@override
public BiConsumer<List<T>, T> accumulator() {
return List::add;
}
25.01.2021 POO 25
Streams – colectare date

@override
public Function<List<T>, List<T>> finisher() {
return Function.identity();
}
@override
public BinaryOperator<List<T>> combiner() {
return (list1, list2) ->
list1.addAll(list2);
return list;
}
}
@override
public Set<Characteristics> characteristics() {
return Collections.unmodifiableSet(enumSet.of(
IDENTITY.FINISH, CONCURRENT));
}
}
25.01.2021 POO 26

S-ar putea să vă placă și