JavaRush /Курси /Java Syntax Zero /Колектори в Java

Колектори в Java

Java Syntax Zero
Рівень 19 , Лекція 7
Відкрита

1. Збір елементів

І нарешті ми дійшли до найцікавішого методу в класі Stream — методу collect(). Він використовується для того, щоб перейти від потоків до звичних колекцій — List<T>, Set<T>, Map<T, R> і інших.

У метод collect() потрібно передати спеціальний об'єкт — collector. Цей об'єкт зчитує всі дані з потоку, перетворює їх у певну колекцію і повертає її. А слідом за ним цю ж колекцію повертає і сам метод collect.

Все це зроблено досить хитро: об'єкт collector має тип Collector<T, A, R> – у нього аж три типи-параметра. Останній тип R — це зазвичай і є тип на зразок List<T>. Тому компілятор може по цьому типу підставити правильний тип результату самого методу collect().

Сподіваюся, ви не дуже заплуталися. У будь-якому разі, самому створювати об'єкти типу Collector вам не потрібно. Достатньо просто скористатися вже готовими об'єктами, які повертають статичні методи класу Collectors.

Клас Collectors

У класу Collectors є кілька статичних методів, які повертають готові об'єкти-колектори на всі випадки життя. Їх кілька десятків, але ми розглянемо найосновніші:

toList()
Об'єкт, який перетворює потік у список — List<T>
toSet()
Об'єкт, який перетворює потік у множину — Set<T>
toMap()
Об'єкт, який перетворює потік в мап — Map<K, V>
joining()
Склеює елементи потоку в один рядок
mapping()
Перетворює елементи потоку в Map<K, V>
groupingBy()
Групує елементи, повертає Map <K, V>

2. Перетворення потоку у список

Ось як виглядає типова робота з потоком і перетворення результату роботи у список

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Привіт", "як", "справи?");

List<String> result = list.stream()
   .filter( s -> Character.isUpperCase(s.charAt(0)) )
   .collect( Collectors.toList() );

Ми отримали потік у колекції, потім у ньому отримали новий потік, відфільтрувавши тільки рядки, перший символ яких — заголовний. Потім всі дані з останнього потоку зібрали у колекцію і повернули її.



3. Перетворення потоку у множину

Ось як виглядає типова робота з потоком і перетворення результату роботи у множину

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Привіт", "як", "справи?");

Set<String> result = list.stream()
   .filter( s -> Character.isUpperCase(s.charAt(0)) )
   .collect( Collectors.toSet() );

Все дуже подібне до коду перетворення потоку в List, тільки використовується інший об'єкт-колектор, який повертає метод toSet();



4. Перетворення потоку в мап

А от перетворити потік у мап трохи складніше. Адже кожен об'єкт Map складається з двох елементів — ключа і значення. Нам потрібно придумати, як у елемента потоку ми визначатимемо ключ, а як — значення.

Приклад.

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "a=2", "b=3", "c=4", "d==3");

Map<String, String> result = list.stream()
   .map( e -> e.split("=") )
   .filter( e -> e.length == 2 )
   .collect( Collectors.toMap(e -> e[0], e -> e[1]) );

Давайте розберемо, що тут відбувається.

У першій строчці map(...) ми перетворюємо кожен рядок у масив рядків. Використовуючи метод split, ми ділимо кожен рядок на дві частини за символом «дорівнює».

У другій строчці — метод filter() — ми пропускаємо через фільтр лише ті елементи-масиви, які містять рівно два елементи. Елемент d == 3 був поділений на масив із трьох елементів, і фільтр не пройде.

І нарешті, в останній строчці ми перетворюємо потік у Map<String, String>. У метод toMap() передаються дві функції. Для кожного елемента потоку перша функція має повернути ключ, а друга — значення.

У нас у якості ключа буде перший елемент масиву ("a", "b", "c"), а у якості значень — другий елемент масиву: "2", "3", "4".



5. Перетворення потоку у рядок

Ще один цікавий об'єкт-колектор — це Collectors.joining(). Він перетворює всі елементи потоку до типу String і склеює їх в один рядок. Приклад

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "a=2", "b=3", "c=4", "d==3");
String result = list.stream().collect( Collectors.joining(", ") );

Коментарі (12)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
IronMan57 Рівень 28
21 січня 2025
IronMan57 Рівень 28
21 січня 2025
Після лекцій, а особливо розв'язання задач цього рівня почуваюсь ніби долучився до якогось таємного знання. Можу за таємними знаками (стрілки, подвійні двокрапки) бачити суть усіх речей. Майбуть, так само себе почувають адепти чорної магії або масони. А ще точно деякі пацієнти психлікарень.
Sava_crosava Рівень 23
3 листопада 2023
Лекція круто розписана, підозрюю що дуууже багато чого недоговорили, але для загального розуміння синтаксису думаю достатньо) За задачі також ставлю +
ecotalisman Рівень 84 Expert
23 липня 2023
Може комусь буде зрозуміліше про collect(): Нам потрібно передати до collect() спеціальний об'єкт, який називається колектор (collector). Колектор "читає" всі дані з потоку, перетворює їх на певну колекцію та повертає цю колекцію. Тоді сам метод collect() повертає цю ж колекцію. Тип об'єкта колектора є Collector<T, A, R>, де: T - тип об'єктів у потоці. A - тип "акумулятора", який збирає об'єкти в процесі перебігу потоку (проміжний тип). R - тип колекції, що повертається. Як правило, ми не створюємо колектори вручну. Замість цього ми використовуємо вже готові колектори, які повертають статичні методи класу Collectors.

List<String> names = Stream.of("John", "Susan", "Kim", "George")
                            .collect(Collectors.toList());
У цьому прикладі ми маємо потік рядків. Метод collect(Collectors.toList()) перетворює цей потік в список (List). Колектор, який повертається методом Collectors.toList(), "читає" кожен елемент потоку та додає його до нового списку. Після того, як всі елементи потоку були оброблені, метод collect() повертає цей список.
16 липня 2023
Чому ми повинні писати просто toList(), toMap() і не можемо писати Collectors.toList()... Я розумію що в import вказаний саме метод, але що такого у тому щоб зайвий раз написати Collectors, що аж компілятор не приймає?
Денис Рівень 111 Expert
22 липня 2023
тому що ідея імпортує статичний метод [import static java.util.stream.Collectors.toMap] Якщо тобі звичніше викликати метод класу то перепиши імпорт на [import java.util.stream.Collectors]
AsVAN Рівень 1 Expert
8 березня 2023
Я би назвав цей блок квесту "Очі бояться, руки роблять"
FAUST_ua Рівень 29
4 жовтня 2022
Зробив легко задачі з даної лекції. Зверніть увагу на наявність/відсутність Stream
Optimuc Рівень 34
14 серпня 2022
Мне интересно, один я не понимаю как вот решить первую задачу не посмотрев ответ?
Roman Рівень 20 Expert
25 серпня 2022
Не знаю, зробив за 1хв
kalkulator¹ Рівень 51
27 листопада 2022
пффф з першого разу за поро сек
unite Рівень 24 Expert
23 лютого 2023
Спочатку фільтруєш за умовою, потів переводиш в Список за наведеним прикладом