Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Вивчайте Stream API у Java | Розширені Можливості та Техніки Java
Структури Даних Java

bookStream API у Java

Існують різні способи обробки даних у Java – цикли, методи та різноманітні алгоритми. Однак у Java 8 було впроваджено дуже потужний інструмент – Stream API.

Простими словами, Stream API – це спосіб швидкої та зручної роботи з потоком інформації. У нашому випадку цей потік інформації представлений колекціями. Stream API має кілька основних понять. Ось головні з них.

Основні поняття

  • Stream: представляє послідовність елементів даних, які можна обробляти;

  • Проміжні операції: операції, які створюють новий потік після виконання. Приклади: filter, map, distinct, sorted;

  • Термінальні операції: операції, які завершують обробку потоку та повертають результат. Приклади: collect, forEach, count, reduce;

  • Паралельні потоки: дозволяють паралельну обробку даних. Для створення паралельних потоків використовуються методи parallel() та parallelStream().

Досить теорії — перейдемо до кодування!

Оголошення потоку здійснюється за допомогою методу колекції, яку потрібно перетворити на потік:

Main.java

Main.java

copy
12
List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream();

За допомогою методу stream() отримано потік рядків. Однак для роботи з потоком необхідно розуміти, що таке лямбда-вирази, оскільки основні методи потоків працюють саме з ними.

Лямбда-вирази

Лямбда-вирази були впроваджені в Java 8 і являють собою спрощену форму створення анонімних функцій у Java. Раніше ми не розглядали анонімні функції, оскільки вони не були особливо необхідні, але тепер ознайомимося з ними через лямбда-вирази.

Синтаксис лямбда-виразів:

Загальний синтаксис лямбда-виразів у Java виглядає так:

Example.java

Example.java

copy
123
(parameters) -> expression // or (parameters) -> { statements; }
  • Параметри: це список параметрів, який може бути порожнім або містити один чи декілька параметрів;

  • Стрілка: позначається символом ->, який відокремлює параметри від тіла лямбда-виразу;

  • Вираз або оператори: це тіло функції, яке містить вираз або блок операторів.

Ось приклад лямбда-виразу, що представляє просту функцію, яка додає два числа:

Example.java

Example.java

copy
12345678910
// Traditional way MathOperation addition = new MathOperation() { @Override public int operate(int a, int b) { return a + b; } }; // Using a lambda expression MathOperation addition = (int a, int b) -> a + b;

Розгляньмо детальніше, що саме відбувається у наведеному вище коді та як ми використовуємо лямбда-вирази:

Main.java

Main.java

copy
1234567891011121314
package com.example; // Functional interface with a single abstract method interface MyMathOperation { int operate(int a, int b); } public class Main { public static void main(String[] args) { // Using a lambda expression to implement the interface MyMathOperation addition = (a, b) -> a + b; System.out.println("Sum: " + addition.operate(5, 3)); } }

У наведеному вище коді:

Створено функціональний інтерфейс MyMathOperation з одним абстрактним методом operate.

Використано лямбда-вираз для реалізації цього методу, що виконує додавання двох чисел.

Виведено результат додавання.

Розумію, що зараз може бути складно зрозуміти, що відбувається у цьому коді, але повернемося до Stream API, де лямбда-вирази часто використовуються, і спробуємо розібратися, як їх застосовувати на практиці.

Як ви пам'ятаєте, раніше ми створили потік рядків зі списку рядків. Тепер використаємо методи потоку, щоб зробити кожен рядок у цьому потоці великими літерами:

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream(); stream.map(e -> e.toUpperCase()).toList(); } }

У наведеному вище коді використано лямбда-вираз і два методи: map() і toList(). Якщо зрозуміло, що робить метод toList(), то метод map() змінює кожен елемент потоку відповідно до наданого лямбда-виразу.

Розглянемо детальніше, як тут працює лямбда-вираз:

Метод map() застосовує метод toUpperCase() до кожного елемента потоку. Ми визначили елемент цього потоку як e і за допомогою лямбда-виразу вказали програмі застосувати цей метод до кожного елемента.

Але це ще не все, оскільки ми застосували проміжну операцію. Це означає, що операції над потоком ще не завершені. Щоб завершити роботу з потоком, потрібно застосувати термінальну операцію, яка завершить операції над потоком і поверне конкретне значення. Наприклад, можна використати метод toList(), і змінений потік буде перетворено на список.

Наприклад:

Main.java

Main.java

copy
1234567891011121314
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream(); List<String> list = stream.map(e -> e.toUpperCase()).toList(); System.out.println(list); } }

Розгляньмо детальніше можливі проміжні операції у стрімі.

Проміжні операції

Метод map() — ви вже знайомі з цим методом; він виконує операції, визначені лямбда-виразом, над кожним елементом стріму.

Наприклад, використаємо метод substring() для кожного елемента у стрімі рядків:

Main.java

Main.java

copy
123456789101112131415
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); Stream<String> stream = strings.stream(); List<String> list = stream.map(e -> e.substring(1, 4)).toList(); System.out.println("Modified list: " + list); } }

Метод filter() приймає лямбда-вираз з умовою, за якою потік буде відфільтровано. Тобто, усі елементи, що відповідають умові, залишаються у потоці, а елементи, які не відповідають умові, видаляються з потоку. Модифікуємо потік так, щоб залишити лише елементи, довжина яких більша за 5:

Main.java

Main.java

copy
12345678910111213141516
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); Stream<String> stream = strings.stream(); stream = stream.filter(e -> e.length() > 5); List<String> list = stream.map(e -> e.substring(1, 4)).toList(); System.out.println("Modified list: " + list); } }

Використовуючи метод filter(), ми видаляємо рядок "with" зі стріму, оскільки це слово містить менше ніж 5 символів.

Також можна використовувати проміжні операції кілька разів поспіль.

Наприклад, ми можемо трохи спростити наведений вище код:

Main.java

Main.java

copy
12345678910111213141516
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); List<String> list = strings.stream() .filter(e -> e.length() > 5) .map(e -> e.substring(1, 4)) .toList(); System.out.println("Modified list: " + list); } }

Під час ланцюжкового виклику декількох методів стріму рекомендується розміщувати кожен метод на новому рядку для значного підвищення читабельності коду.

Метод flatMap() перетворює кожен елемент потоку на новий потік і об'єднує результати в один потік. Іншими словами, за допомогою цього методу можна розділити потік на підпотоки, які потім будуть об'єднані в один потік. Наприклад, у вас є список рядків, де кожен рядок може містити декілька слів, як-от список імен і прізвищ. І потрібно зробити першу літеру кожного з цих слів великою:

Main.java

Main.java

copy
123456789101112131415161718192021222324
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<String> users = Arrays.asList("Ethan Johnson", "Olivia smith", "mason davis", "Ava taylor", "logan brown", "Emma Anderson", "jackson miller"); System.out.println("List of users: " + users); List<String> list = users.stream() .flatMap(e -> Arrays.stream(e.split(" "))) .map(e -> capitalizeFirstLetter(e)) .toList(); System.out.println("List with capitalized names and surnames: " + list); } private static String capitalizeFirstLetter(String word) { if (word == null || word.isEmpty()) { return word; } return Character.toUpperCase(word.charAt(0)) + word.substring(1); } }

У наведеному вище коді ми написали окремий приватний метод, який робить першу літеру слова великою, і використали цей метод у методі map() разом із лямбда-виразом.

Зверніть увагу, що використовуючи метод flatMap, ми розділяємо кожен елемент потоку на окремі потоки за допомогою методу Arrays.stream(e.split(" ")). Оскільки метод split() повертає масив, потрібно скористатися методом Arrays.stream(), щоб розбити цей масив на потоки.

Після цього всі ці потоки об'єднуються в один потік, після чого ми використовуємо написаний нами метод. Тепер у нас є всі імена та прізвища користувачів з великої літери.

Знаєте, що було б цікаво? Якщо ми помістимо ці імена та прізвища у HashMap, де ключем буде прізвище, а значенням — ім'я.

Реалізуємо це в коді:

Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031323334
package com.example; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; public class Main { public static void main(String[] args) { List<String> users = Arrays.asList("Ethan Johnson", "Olivia smith", "mason davis", "Ava taylor", "logan brown", "Emma Anderson", "jackson miller"); System.out.println("List of users: " + users); List<String> list = users.stream() .flatMap(e -> Arrays.stream(e.split(" "))) .map(e -> capitalizeFirstLetter(e)) .toList(); System.out.println("List with capitalized names and surnames: " + list); Map<String, String> usersKeyValue = new HashMap<>(); for (int i = 0; i < list.size() - 1; i+=2) { String name = list.get(i); String surname = list.get(i + 1); usersKeyValue.put(surname, name); } System.out.println("Map with surnames as keys and names as values: " + usersKeyValue); } private static String capitalizeFirstLetter(String word) { if (word == null || word.isEmpty()) { return word; } return Character.toUpperCase(word.charAt(0)) + word.substring(1); } }

За допомогою простого циклу ми зберегли ім'я та прізвище у змінних, а потім у мапі. Зверніть увагу, як працює цикл. Ми збільшуємо змінну i на 2 у кожній ітерації, оскільки потрібно пропустити прізвище після того, як вже його записали.

  • Метод distinct() видаляє дублікати зі стріму. Загалом це корисно, якщо потрібні унікальні елементи у стрімі або якщо потрібно швидко прибрати дублікати зі списку. Це легко реалізувати за допомогою такої конструкції:
list.stream().distinct().toList()
  • Метод sorted сортує всі елементи у стрімі у природному порядку, від найменшого до найбільшого числа або в алфавітному порядку. Це також корисно, якщо потрібен відсортований стрім або потрібно швидко відсортувати список;

  • Метод skip(n) пропускає перші n елементів стріму. Це може бути корисно при роботі з текстовими файлами, де перші n рядків можуть бути, наприклад, метаданими або описом файлу. Також варто згадати метод limit(n), який зазвичай обмежує кількість елементів у стрімі. Навіть якщо ми створимо стрім із 1000 елементів і потім використаємо limit(200), у стрімі залишаться лише перші 200 елементів.

Main.java

Main.java

copy
123456789101112
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); example = example.stream().skip(3).limit(5).toList(); System.out.println("List: " + example); } }

Це основні проміжні методи, які необхідно використовувати. Інші методи можна дослідити, звернувшись до посилання на офіційну документацію Java. Далі розглянемо термінальні методи.

Термінальні методи

  • Термінальний метод, з яким ви вже знайомі, — це toList(). Він перетворює стрім у список і повертає його. Тобто, можна безпосередньо присвоїти цей стрім із методами до списку. Цей метод з’явився у Java 17 і є заміною для складнішої конструкції collect(Collectors.toList());

  • Метод collect() також перетворює стрім у певну структуру даних. Як параметр він використовує метод із інтерфейсу Collectors. Цей інтерфейс містить такі методи, як toList(), toSet(), та toCollection(). Наприклад:

Main.java

Main.java

copy
123456789101112131415
package com.example; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Set<Integer> integerSet = example.stream().collect(Collectors.toSet()); System.out.println("List: " + example); System.out.println("Set: " + integerSet); } }

Метод forEach() приймає лямбда-вираз і виконує певну дію для кожного елемента потоку.

Наприклад:

Main.java

Main.java

copy
1234567891011
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); example.stream().forEach(e -> System.out.println(e + 1)); } }

Відмінність між цим методом та методом map полягає в тому, що цей метод є термінальним, і після нього не можна викликати інші методи.

Це всі базові методи для роботи зі стрімами. Це складна тема, і можливо, ви не зрозумієте її одразу. Проте це питання, яке опановується на практиці. У наступних практичних розділах зі стрімами у вас буде багато можливостей попрацювати з ними, адже це дуже зручний і практичний спосіб обробки списків та масивів даних!

1. Яке основне призначення Stream API в Java?

2. Яка з наведених операцій є термінальною в Stream API?

3. Що виконує операція map у Stream API?

4. Чим відрізняється операція flatMap від map у Stream API?

5. Що виконує операція filter у Stream API?

6. Яке призначення операції forEach у Stream API?

7. Яка з наведених операцій є проміжною у Stream API?

8. Як використовується операція limit у Stream API?

question mark

Яке основне призначення Stream API в Java?

Select the correct answer

question mark

Яка з наведених операцій є термінальною в Stream API?

Select the correct answer

question mark

Що виконує операція map у Stream API?

Select the correct answer

question mark

Чим відрізняється операція flatMap від map у Stream API?

Select the correct answer

question mark

Що виконує операція filter у Stream API?

Select the correct answer

question mark

Яке призначення операції forEach у Stream API?

Select the correct answer

question mark

Яка з наведених операцій є проміжною у Stream API?

Select the correct answer

question mark

Як використовується операція limit у Stream API?

Select the correct answer

Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 4. Розділ 3

Запитати АІ

expand

Запитати АІ

ChatGPT

Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат

bookStream API у Java

Свайпніть щоб показати меню

Існують різні способи обробки даних у Java – цикли, методи та різноманітні алгоритми. Однак у Java 8 було впроваджено дуже потужний інструмент – Stream API.

Простими словами, Stream API – це спосіб швидкої та зручної роботи з потоком інформації. У нашому випадку цей потік інформації представлений колекціями. Stream API має кілька основних понять. Ось головні з них.

Основні поняття

  • Stream: представляє послідовність елементів даних, які можна обробляти;

  • Проміжні операції: операції, які створюють новий потік після виконання. Приклади: filter, map, distinct, sorted;

  • Термінальні операції: операції, які завершують обробку потоку та повертають результат. Приклади: collect, forEach, count, reduce;

  • Паралельні потоки: дозволяють паралельну обробку даних. Для створення паралельних потоків використовуються методи parallel() та parallelStream().

Досить теорії — перейдемо до кодування!

Оголошення потоку здійснюється за допомогою методу колекції, яку потрібно перетворити на потік:

Main.java

Main.java

copy
12
List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream();

За допомогою методу stream() отримано потік рядків. Однак для роботи з потоком необхідно розуміти, що таке лямбда-вирази, оскільки основні методи потоків працюють саме з ними.

Лямбда-вирази

Лямбда-вирази були впроваджені в Java 8 і являють собою спрощену форму створення анонімних функцій у Java. Раніше ми не розглядали анонімні функції, оскільки вони не були особливо необхідні, але тепер ознайомимося з ними через лямбда-вирази.

Синтаксис лямбда-виразів:

Загальний синтаксис лямбда-виразів у Java виглядає так:

Example.java

Example.java

copy
123
(parameters) -> expression // or (parameters) -> { statements; }
  • Параметри: це список параметрів, який може бути порожнім або містити один чи декілька параметрів;

  • Стрілка: позначається символом ->, який відокремлює параметри від тіла лямбда-виразу;

  • Вираз або оператори: це тіло функції, яке містить вираз або блок операторів.

Ось приклад лямбда-виразу, що представляє просту функцію, яка додає два числа:

Example.java

Example.java

copy
12345678910
// Traditional way MathOperation addition = new MathOperation() { @Override public int operate(int a, int b) { return a + b; } }; // Using a lambda expression MathOperation addition = (int a, int b) -> a + b;

Розгляньмо детальніше, що саме відбувається у наведеному вище коді та як ми використовуємо лямбда-вирази:

Main.java

Main.java

copy
1234567891011121314
package com.example; // Functional interface with a single abstract method interface MyMathOperation { int operate(int a, int b); } public class Main { public static void main(String[] args) { // Using a lambda expression to implement the interface MyMathOperation addition = (a, b) -> a + b; System.out.println("Sum: " + addition.operate(5, 3)); } }

У наведеному вище коді:

Створено функціональний інтерфейс MyMathOperation з одним абстрактним методом operate.

Використано лямбда-вираз для реалізації цього методу, що виконує додавання двох чисел.

Виведено результат додавання.

Розумію, що зараз може бути складно зрозуміти, що відбувається у цьому коді, але повернемося до Stream API, де лямбда-вирази часто використовуються, і спробуємо розібратися, як їх застосовувати на практиці.

Як ви пам'ятаєте, раніше ми створили потік рядків зі списку рядків. Тепер використаємо методи потоку, щоб зробити кожен рядок у цьому потоці великими літерами:

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream(); stream.map(e -> e.toUpperCase()).toList(); } }

У наведеному вище коді використано лямбда-вираз і два методи: map() і toList(). Якщо зрозуміло, що робить метод toList(), то метод map() змінює кожен елемент потоку відповідно до наданого лямбда-виразу.

Розглянемо детальніше, як тут працює лямбда-вираз:

Метод map() застосовує метод toUpperCase() до кожного елемента потоку. Ми визначили елемент цього потоку як e і за допомогою лямбда-виразу вказали програмі застосувати цей метод до кожного елемента.

Але це ще не все, оскільки ми застосували проміжну операцію. Це означає, що операції над потоком ще не завершені. Щоб завершити роботу з потоком, потрібно застосувати термінальну операцію, яка завершить операції над потоком і поверне конкретне значення. Наприклад, можна використати метод toList(), і змінений потік буде перетворено на список.

Наприклад:

Main.java

Main.java

copy
1234567891011121314
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream(); List<String> list = stream.map(e -> e.toUpperCase()).toList(); System.out.println(list); } }

Розгляньмо детальніше можливі проміжні операції у стрімі.

Проміжні операції

Метод map() — ви вже знайомі з цим методом; він виконує операції, визначені лямбда-виразом, над кожним елементом стріму.

Наприклад, використаємо метод substring() для кожного елемента у стрімі рядків:

Main.java

Main.java

copy
123456789101112131415
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); Stream<String> stream = strings.stream(); List<String> list = stream.map(e -> e.substring(1, 4)).toList(); System.out.println("Modified list: " + list); } }

Метод filter() приймає лямбда-вираз з умовою, за якою потік буде відфільтровано. Тобто, усі елементи, що відповідають умові, залишаються у потоці, а елементи, які не відповідають умові, видаляються з потоку. Модифікуємо потік так, щоб залишити лише елементи, довжина яких більша за 5:

Main.java

Main.java

copy
12345678910111213141516
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); Stream<String> stream = strings.stream(); stream = stream.filter(e -> e.length() > 5); List<String> list = stream.map(e -> e.substring(1, 4)).toList(); System.out.println("Modified list: " + list); } }

Використовуючи метод filter(), ми видаляємо рядок "with" зі стріму, оскільки це слово містить менше ніж 5 символів.

Також можна використовувати проміжні операції кілька разів поспіль.

Наприклад, ми можемо трохи спростити наведений вище код:

Main.java

Main.java

copy
12345678910111213141516
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); List<String> list = strings.stream() .filter(e -> e.length() > 5) .map(e -> e.substring(1, 4)) .toList(); System.out.println("Modified list: " + list); } }

Під час ланцюжкового виклику декількох методів стріму рекомендується розміщувати кожен метод на новому рядку для значного підвищення читабельності коду.

Метод flatMap() перетворює кожен елемент потоку на новий потік і об'єднує результати в один потік. Іншими словами, за допомогою цього методу можна розділити потік на підпотоки, які потім будуть об'єднані в один потік. Наприклад, у вас є список рядків, де кожен рядок може містити декілька слів, як-от список імен і прізвищ. І потрібно зробити першу літеру кожного з цих слів великою:

Main.java

Main.java

copy
123456789101112131415161718192021222324
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<String> users = Arrays.asList("Ethan Johnson", "Olivia smith", "mason davis", "Ava taylor", "logan brown", "Emma Anderson", "jackson miller"); System.out.println("List of users: " + users); List<String> list = users.stream() .flatMap(e -> Arrays.stream(e.split(" "))) .map(e -> capitalizeFirstLetter(e)) .toList(); System.out.println("List with capitalized names and surnames: " + list); } private static String capitalizeFirstLetter(String word) { if (word == null || word.isEmpty()) { return word; } return Character.toUpperCase(word.charAt(0)) + word.substring(1); } }

У наведеному вище коді ми написали окремий приватний метод, який робить першу літеру слова великою, і використали цей метод у методі map() разом із лямбда-виразом.

Зверніть увагу, що використовуючи метод flatMap, ми розділяємо кожен елемент потоку на окремі потоки за допомогою методу Arrays.stream(e.split(" ")). Оскільки метод split() повертає масив, потрібно скористатися методом Arrays.stream(), щоб розбити цей масив на потоки.

Після цього всі ці потоки об'єднуються в один потік, після чого ми використовуємо написаний нами метод. Тепер у нас є всі імена та прізвища користувачів з великої літери.

Знаєте, що було б цікаво? Якщо ми помістимо ці імена та прізвища у HashMap, де ключем буде прізвище, а значенням — ім'я.

Реалізуємо це в коді:

Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031323334
package com.example; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; public class Main { public static void main(String[] args) { List<String> users = Arrays.asList("Ethan Johnson", "Olivia smith", "mason davis", "Ava taylor", "logan brown", "Emma Anderson", "jackson miller"); System.out.println("List of users: " + users); List<String> list = users.stream() .flatMap(e -> Arrays.stream(e.split(" "))) .map(e -> capitalizeFirstLetter(e)) .toList(); System.out.println("List with capitalized names and surnames: " + list); Map<String, String> usersKeyValue = new HashMap<>(); for (int i = 0; i < list.size() - 1; i+=2) { String name = list.get(i); String surname = list.get(i + 1); usersKeyValue.put(surname, name); } System.out.println("Map with surnames as keys and names as values: " + usersKeyValue); } private static String capitalizeFirstLetter(String word) { if (word == null || word.isEmpty()) { return word; } return Character.toUpperCase(word.charAt(0)) + word.substring(1); } }

За допомогою простого циклу ми зберегли ім'я та прізвище у змінних, а потім у мапі. Зверніть увагу, як працює цикл. Ми збільшуємо змінну i на 2 у кожній ітерації, оскільки потрібно пропустити прізвище після того, як вже його записали.

  • Метод distinct() видаляє дублікати зі стріму. Загалом це корисно, якщо потрібні унікальні елементи у стрімі або якщо потрібно швидко прибрати дублікати зі списку. Це легко реалізувати за допомогою такої конструкції:
list.stream().distinct().toList()
  • Метод sorted сортує всі елементи у стрімі у природному порядку, від найменшого до найбільшого числа або в алфавітному порядку. Це також корисно, якщо потрібен відсортований стрім або потрібно швидко відсортувати список;

  • Метод skip(n) пропускає перші n елементів стріму. Це може бути корисно при роботі з текстовими файлами, де перші n рядків можуть бути, наприклад, метаданими або описом файлу. Також варто згадати метод limit(n), який зазвичай обмежує кількість елементів у стрімі. Навіть якщо ми створимо стрім із 1000 елементів і потім використаємо limit(200), у стрімі залишаться лише перші 200 елементів.

Main.java

Main.java

copy
123456789101112
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); example = example.stream().skip(3).limit(5).toList(); System.out.println("List: " + example); } }

Це основні проміжні методи, які необхідно використовувати. Інші методи можна дослідити, звернувшись до посилання на офіційну документацію Java. Далі розглянемо термінальні методи.

Термінальні методи

  • Термінальний метод, з яким ви вже знайомі, — це toList(). Він перетворює стрім у список і повертає його. Тобто, можна безпосередньо присвоїти цей стрім із методами до списку. Цей метод з’явився у Java 17 і є заміною для складнішої конструкції collect(Collectors.toList());

  • Метод collect() також перетворює стрім у певну структуру даних. Як параметр він використовує метод із інтерфейсу Collectors. Цей інтерфейс містить такі методи, як toList(), toSet(), та toCollection(). Наприклад:

Main.java

Main.java

copy
123456789101112131415
package com.example; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Set<Integer> integerSet = example.stream().collect(Collectors.toSet()); System.out.println("List: " + example); System.out.println("Set: " + integerSet); } }

Метод forEach() приймає лямбда-вираз і виконує певну дію для кожного елемента потоку.

Наприклад:

Main.java

Main.java

copy
1234567891011
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); example.stream().forEach(e -> System.out.println(e + 1)); } }

Відмінність між цим методом та методом map полягає в тому, що цей метод є термінальним, і після нього не можна викликати інші методи.

Це всі базові методи для роботи зі стрімами. Це складна тема, і можливо, ви не зрозумієте її одразу. Проте це питання, яке опановується на практиці. У наступних практичних розділах зі стрімами у вас буде багато можливостей попрацювати з ними, адже це дуже зручний і практичний спосіб обробки списків та масивів даних!

1. Яке основне призначення Stream API в Java?

2. Яка з наведених операцій є термінальною в Stream API?

3. Що виконує операція map у Stream API?

4. Чим відрізняється операція flatMap від map у Stream API?

5. Що виконує операція filter у Stream API?

6. Яке призначення операції forEach у Stream API?

7. Яка з наведених операцій є проміжною у Stream API?

8. Як використовується операція limit у Stream API?

question mark

Яке основне призначення Stream API в Java?

Select the correct answer

question mark

Яка з наведених операцій є термінальною в Stream API?

Select the correct answer

question mark

Що виконує операція map у Stream API?

Select the correct answer

question mark

Чим відрізняється операція flatMap від map у Stream API?

Select the correct answer

question mark

Що виконує операція filter у Stream API?

Select the correct answer

question mark

Яке призначення операції forEach у Stream API?

Select the correct answer

question mark

Яка з наведених операцій є проміжною у Stream API?

Select the correct answer

question mark

Як використовується операція limit у Stream API?

Select the correct answer

Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 4. Розділ 3
some-alt