MySQL Java JavaScript PHP Python HTML-CSS C-sharp C++ Go

Filtrare, parcurgerea elementelor și mapare

Parcurgerea elementelor - Metoda forEach

Pentru parcurgerea elementelor unui flux se utilizează metoda forEach(), care reprezintă o operație terminală. Ca parametru, aceasta acceptă un obiect de tip Consumer<? super String>, care definește acțiunea ce va fi efectuată pentru fiecare element din set. De exemplu:

Stream<String> citiesStream = Stream.of("Paris", "Londra", "Madrid", "Berlin", "Bruxelles");
citiesStream.forEach(s -> System.out.println(s));

Aceasta va fi echivalentă cu parcurgerea tuturor elementelor într-un ciclu for și executarea acțiunii pentru fiecare element, adică afișarea la consolă. Rezultatul afișat pe consolă va fi:

Paris  
Londra  
Madrid  
Berlin  
Bruxelles

Putem simplifica utilizarea metodei forEach astfel:

Stream<String> citiesStream = Stream.of("Paris", "Londra", "Madrid", "Berlin", "Bruxelles");
citiesStream.forEach(System.out::println);

În acest caz, se transmite o referință la metoda statică care afișează șirul la consolă.

Filtrarea - Metoda filter

Pentru filtrarea elementelor din flux se folosește metoda filter(), care reprezintă o operație intermediară. Aceasta acceptă ca parametru o condiție sub forma unui obiect Predicate<T> și returnează un flux nou cu elementele care îndeplinesc această condiție:

Stream<String> citiesStream = Stream.of("Paris", "Londra", "Madrid", "Berlin", "Bruxelles");
citiesStream.filter(s -> s.length() == 6).forEach(s -> System.out.println(s));

Condiția s.length() == 6 returnează true pentru elementele a căror lungime este de 6 caractere. Astfel, rezultatul afișat va fi:

Londra  
Madrid  
Berlin

Să analizăm un alt exemplu de filtrare cu date mai complexe. Să presupunem că avem următoarea clasă Phone:

class Phone{
   
   private String name;
   private int price;
   
   public Phone(String name, int price){
       this.name=name;
       this.price=price;
   }
   
   public String getName() {
       return name;
   }
   
   public void setName(String name) {
       this.name = name;
   }
   
   public int getPrice() {
       return price;
   }
   
   public void setPrice(int price) {
       this.price = price;
   }
}

Filtrăm setul de telefoane în funcție de preț:

Stream<Phone> phoneStream = Stream.of(new Phone("iPhone 6 S", 54000), new Phone("Lumia 950", 45000),
               new Phone("Samsung Galaxy S 6", 40000));

phoneStream.filter(p -> p.getPrice() < 50000).forEach(p -> System.out.println(p.getName()));

Mapare - Metoda map

Maparea sau transformarea permite definirea unei funcții de conversie a unui obiect într-altul, adică obținerea unui element de un alt tip din elementul existent. Pentru mapare se folosește metoda map(), care are următoarea definiție:

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

Funcția transmisă în metoda map definește transformarea obiectelor de tip T în obiecte de tip R. În rezultat, se returnează un flux nou cu obiectele transformate.

Să folosim clasa Phone definită anterior și să efectuăm o transformare de la tipul Phone la tipul String:

Stream<Phone> phoneStream = Stream.of(new Phone("iPhone 6 S", 54000), new Phone("Lumia 950", 45000),
               new Phone("Samsung Galaxy S 6", 40000));

phoneStream
   .map(p -> p.getName()) // introducem în flux doar numele telefoanelor
   .forEach(s -> System.out.println(s));

Operația map(p -> p.getName()) introduce în noul flux doar numele telefoanelor. Pe consolă vor fi afișate doar numele:

iPhone 6 S  
Lumia 950 
Samsung Galaxy S 6

Să efectuăm alte transformări:

phoneStream
   .map(p -> "nume: " + p.getName() + " preț: " + p.getPrice())
   .forEach(s -> System.out.println(s));

În acest caz, fluxul rezultat conține doar șiruri de caractere, iar numele sunt combinate cu prețurile.

Pentru transformarea obiectelor în tipuri Integer, Long, Double sunt definite metode speciale: mapToInt(), mapToLong() și mapToDouble().

Mapare plată - Metoda flatMap

Maparea plată se efectuează atunci când dintr-un element trebuie să obținem mai multe. Această operațiune este realizată de metoda flatMap():

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

De exemplu, în exemplul anterior afișăm numele telefonului și prețul acestuia. Dar dacă dorim să stabilim pentru fiecare telefon un preț fără reducere și unul cu reducere? Adică dintr-un obiect Phone să obținem două obiecte cu informații, de exemplu, sub formă de șiruri de caractere. Pentru aceasta, utilizăm flatMap():

Stream<Phone> phoneStream = Stream.of(new Phone("iPhone 6 S", 54000), new Phone("Lumia 950", 45000),
               new Phone("Samsung Galaxy S 6", 40000));

phoneStream
   .flatMap(p -> Stream.of(
           String.format("nume: %s preț fără reducere: %d", p.getName(), p.getPrice()),
           String.format("nume: %s preț cu reducere: %d", p.getName(), p.getPrice() - (int)(p.getPrice() * 0.1))
   ))
   .forEach(s -> System.out.println(s));

Rezultatul programului va fi:

nume: iPhone 6 S preț fără reducere: 54000 
nume: iPhone 6 S preț cu reducere: 48600 
nume: Lumia 950 preț fără reducere: 45000 
nume: Lumia 950 preț cu reducere: 40500 
nume: Samsung Galaxy S 6 preț fără reducere: 40000 
nume: Samsung Galaxy S 6 preț cu reducere: 36000