Метод collect

Последнее обновление: 29.04.2018

Большинство операций класса Stream, которые модифицируют набор данных, возвращают этот набор в виде потока. Однако бывают ситуации, когда хотелось бы получить данные не в виде потока, а в виде обычной коллекции, например, ArrayList или HashSet. И для этого у класса Stream определен метод collect. Первая версия метода принимает в качестве параметра функцию преобразования к коллекции:

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

Параметр R представляет тип результата метода, параметр Т - тип элемента в потоке, а параметр А - тип промежуточных накапливаемых данных. В итоге параметр collector представляет функцию преобразования потока в коллекцию.

Эта функция представляет объект Collector, который определен в пакете java.util.stream. Мы можем написать свою реализацию функции, однако Java уже предоставляет ряд встроенных функций, определенных в классе Collectors:

  • toList(): преобразование к типу List

  • toSet(): преобразование к типу Set

  • toMap(): преобразование к типу Map

Например, преобразуем набор в потоке в список:

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);
		}
    } 
}

Использование метода toSet() аналогично.

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

Для применения метода toMap() надо задать ключ и значение. Например, пусть у нас есть следующая модель:

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;
    }
}

Теперь применим метод 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; }
}

Лямбда-выражение p->p.getName() получает значение для ключа элемента, а t->t.getPrice() - извлекает значение элемента.

Если нам надо создать какой-то определенный тип коллекции, например, HashSet, то мы можем использовать специальные функции, которые определены в классах-коллекций. Например, получим объект 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));
    } 
}

Выражение HashSet::new представляет функцию создания коллекции. Аналогичным образом можно получать другие коллекции, например, ArrayList:

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

Вторая форма метода collect имеет три параметра:

<R> R collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner)
  • supplier: создает объект коллекции

  • accumulator: добавляет элемент в коллекцию

  • combiner: бинарная функция, которая объединяет два объекта

Применим эту версию метода 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>(), // создаем ArrayList
                (list, item)->list.add(item), // добавляем в список элемент
                (list1, list2)-> list1.addAll(list2)); // добавляем в список другой список
         
		filteredPhones.forEach(s->System.out.println(s));
    } 
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850