Введення в Stream API. Створення потоку даних
Введення в Stream API. Створення потоку даних – уроки java
Введення в Stream API у Java
Stream API було введено в Java 8 і призначене для роботи з колекціями даних у функціональному стилі. Потоки дозволяють обробляти дані декларативно (через послідовні операції) і підтримують такі можливості, як фільтрація, сортування, перетворення елементів, а також агрегування даних. Stream API полегшує обробку великих обсягів даних завдяки можливості використовувати як послідовні, так і паралельні операції.
Основні концепції Stream API
- Потік (Stream) — це послідовність елементів, яка підтримує лінейні операції, що можуть обробляти дані без збереження їх у пам’яті. Потоки не змінюють джерела даних (тобто вони не змінюють колекцію, з якої беруться елементи).
- Ліниві обчислення — потоки підтримують ланцюгові операції, що виконуються тільки тоді, коли запускається кінцева операція (наприклад, `collect()`, `forEach()` тощо).
- Типи операцій:
- Проміжні (intermediate): ці операції виконуються при обробці даних і повертають новий потік (наприклад, `map()`, `filter()`, `sorted()`).
- Кінцеві (terminal): ці операції запускають обробку всього потоку і повертають результат (наприклад, `collect()`, `forEach()`, `count()`).
Створення потоку даних
Потоки можуть бути створені з різних джерел даних, таких як колекції, масиви, файли та інші ресурси. Найпоширеніший спосіб — це створення потоку з колекцій або масивів.
Створення потоку з колекцій
Метод `stream()` використовується для створення потоку з колекцій (наприклад, `List`, `Set` тощо).
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
// Створюємо список
List<String> names = Arrays.asList(“Андрій”, “Ольга”, “Іван”, “Марія”);
// Створюємо потік з колекції
Stream<String> nameStream = names.stream();
// Обробляємо потік: фільтруємо і виводимо на екран
nameStream
.filter(name -> name.startsWith(“А”))
.forEach(System.out::println);
}
}
Виведення:
Андрій
У цьому прикладі ми створюємо потік з колекції `List`, фільтруємо імена, які починаються на букву “А”, і виводимо їх на екран за допомогою кінцевої операції `forEach()`.
Створення потоку з масивів
Для створення потоку з масивів використовується метод `Arrays.stream()` або метод `Stream.of()`.
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
// Створюємо масив
String[] names = {“Олег”, “Аня”, “Максим”, “Дмитро”};
// Створюємо потік з масиву
Stream<String> nameStream = Stream.of(names);
// Обробляємо потік: фільтруємо і виводимо на екран
nameStream
.filter(name -> name.length() > 4)
.forEach(System.out::println);
}
}
Виведення:
Максим
Дмитро
Створення нескінченних потоків
За допомогою методу `Stream.generate()` або `Stream.iterate()` можна створювати нескінченні потоки. Це корисно, якщо потрібно працювати з нескінченними послідовностями даних.
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
// Створюємо нескінченний потік за допомогою iterate()
Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 2);
// Обмежуємо кількість елементів і виводимо їх на екран
infiniteStream
.limit(5)
.forEach(System.out::println);
}
}
Виведення:
0
2
4
6
8
Основні операції з потоками
- `filter(Predicate)` — фільтрує елементи потоку на основі умови.
stream.filter(s -> s.length() > 3); - `map(Function)` — перетворює елементи потоку.
stream.map(String::toUpperCase); - `sorted()` — сортує елементи потоку.
stream.sorted(); - `distinct()` — видаляє дублікати.
stream.distinct(); - `limit(n)` — обмежує кількість елементів у потоці.
stream.limit(5); - `skip(n)` — пропускає перші `n` елементів у потоці.
stream.skip(3); - Кінцеві операції:`forEach(Consumer)` — виконує дію для кожного елемента потоку.
stream.forEach(System.out::println); - `collect(Collector)` — збирає елементи потоку в колекцію або іншу структуру даних.
List<String> result = stream.collect(Collectors.toList()); - `count()` — повертає кількість елементів у потоці.
long count = stream.count(); - `reduce(BinaryOperator)` — агрегує елементи потоку в одне значення.
int sum = stream.reduce(0, Integer::sum);
Паралельні потоки
Паралельні потоки використовуються для розподілу обробки даних між кількома потоками, що може суттєво збільшити продуктивність при роботі з великими колекціями.
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Створюємо паралельний потік
int sum = numbers.parallelStream()
.filter(n -> n % 2 == 0)
.reduce(0, Integer::sum);
System.out.println(“Сума парних чисел: ” + sum);
}
}
Виведення:
Сума парних чисел: 30
У цьому прикладі використовуються паралельні потоки для ефективної обробки чисел. Потік розподіляє обробку між кількома потоками JVM.
Висновок
Stream API — це потужний інструмент для обробки даних у функціональному стилі. Він дозволяє легко виконувати операції над колекціями, фільтрувати, перетворювати, агрегувати дані та працювати з великими обсягами інформації більш ефективно завдяки паралельним потокам.