MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Metoda collect

Majoritatea operațiilor clasei Stream, care modifică un set de date, returnează acest set sub forma unui flux (stream). Totuși, există situații în care am dori să obținem datele nu sub forma unui flux, ci sub forma unei colecții obișnuite, de exemplu, ArrayList sau HashSet. Pentru aceasta, clasa Stream are definită metoda collect.

Prima versiune a metodei acceptă ca parametru o funcție de conversie într-o colecție:

<R,A> R collect(Collector<? super T,A,R> collector)

Parametrul R reprezintă tipul rezultatului metodei, parametrul T - tipul elementului din flux, iar parametrul A - tipul datelor intermediare acumulate. În final, parametrul collector reprezintă funcția de conversie a fluxului într-o colecție.

Această funcție reprezintă obiectul Collector, care este definit în pachetul java.util.stream. Putem scrie propria implementare a funcției, însă Java oferă deja câteva funcții încorporate definite în clasa Collectors:

  • toList(): conversia într-un List
  • toSet(): conversia într-un Set
  • toMap(): conversia într-un Map

De exemplu, să convertim un set din flux într-o listă:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class Program {
   public static void main(String[] args) {
       List<String> phones = new ArrayList<String>();
       Collections.addAll(phones, "iPhone 8", "HTC U12", "Huawei Nexus 6P",
               "Samsung Galaxy S9", "LG G6", "Xiaomi MI6", "ASUS Zenfone 2",
               "Sony Xperia Z5", "Meizu Pro 6", "Lenovo S850");
         
       List<String> filteredPhones = phones.stream()
               .filter(s -> s.length() < 10)
               .collect(Collectors.toList());
               
       for (String s : filteredPhones) {
           System.out.println(s);
       }
   }
}

Utilizarea metodei toSet() este similară:

Set<String> filteredPhones = phones.stream()
               .filter(s -> s.length() < 10)
               .collect(Collectors.toSet());

Pentru utilizarea metodei toMap(), trebuie să specificăm cheia și valoarea. De exemplu, să presupunem că avem următorul model:

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 int getPrice() {
       return price;
   }
}

Acum aplicăm metoda toMap():

import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Program {

   public static void main(String[] args) {
       
       Stream<Phone> phoneStream = Stream.of(new Phone("iPhone 8", 54000),
           new Phone("Nokia 9", 45000),
           new Phone("Samsung Galaxy S9", 40000),
           new Phone("LG G6", 32000));
         
         
       Map<String, Integer> phones = phoneStream
           .collect(Collectors.toMap(p->p.getName(), t->t.getPrice()));
     
       phones.forEach((k,v)->System.out.println(k + " " + v));
   }
}
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 int getPrice() { return price; }
}

Expresia lambda p -> p.getName() obține valoarea pentru cheia elementului, iar t -> t.getPrice() extrage valoarea elementului.

Dacă trebuie să creăm un tip specific de colecție, de exemplu, HashSet, putem folosi funcții speciale definite în clasele colecțiilor. De exemplu, pentru a obține un obiect HashSet:

import java.util.HashSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Program {
   public static void main(String[] args) {
       Stream<String> phones = Stream.of("iPhone 8", "HTC U12", "Huawei Nexus 6P",
               "Samsung Galaxy S9", "LG G6", "Xiaomi MI6", "ASUS Zenfone 2",
               "Sony Xperia Z5", "Meizu Pro 6", "Lenovo S850");
         
       HashSet<String> filteredPhones = phones.filter(s -> s.length() < 12)
                                   .collect(Collectors.toCollection(HashSet::new));
       
       filteredPhones.forEach(s -> System.out.println(s));
   }
}

Expresia HashSet::new reprezintă funcția de creare a colecției. În mod similar, putem obține și alte colecții, de exemplu, ArrayList:

ArrayList<String> result = phones.collect(Collectors.toCollection(ArrayList::new));

A doua formă a metodei collect are trei parametri:

<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner)
  • supplier: creează obiectul colecției
  • accumulator: adaugă un element în colecție
  • combiner: funcție binară care unește două obiecte

Să aplicăm această versiune a metodei collect:

import java.util.ArrayList;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Program {
   public static void main(String[] args) {
       Stream<String> phones = Stream.of("iPhone 8", "HTC U12", "Huawei Nexus 6P",
               "Samsung Galaxy S9", "LG G6", "Xiaomi MI6", "ASUS Zenfone 2",
               "Sony Xperia Z5", "Meizu Pro 6", "Lenovo S850");
 
       ArrayList<String> filteredPhones = phones.filter(s -> s.length() < 12)
           .collect(
               () -> new ArrayList<String>(), // creăm un ArrayList
               (list, item) -> list.add(item), // adăugăm un element în listă
               (list1, list2) -> list1.addAll(list2)); // adăugăm o listă în altă listă
         
       filteredPhones.forEach(s -> System.out.println(s));
   }
}
← Lecția anterioară Lecția următoare →