Поняття кінцевої та проміжної операції. Відмінності. Приклади. Методи створення потоку даних stream(), parallelStream()
Зміст
- 1. Кінцева та проміжна операції. Визначення
- 2. Кінцева операція. Приклад
- 3. Проміжна операція. Приклад
- 4. Формування нових потоків даних з допомогою конвеєру. Приклад
- 5. Приклади отримання (відкриття) потоку даних. Методи stream(), parallelStream()
- Зв’язані теми
Пошук на інших ресурсах:
1. Кінцева та проміжна операції. Визначення
Під операцією мається на увазі виклик якогось методу, що обробляє потік. При обробці потоку виникають поняття кінцевої операції та проміжної операції.
Якщо у визначенні методу описується термін “кінцева операція“, то це означає що переглянуто (оброблено) увесь потік з початку до кінця і отримано кінцевий результат. Після цього даний потік вважається спожитим і його використовувати не можна. Якщо спробувати обробити спожитий потік після виконання кінцевої операції (методу), то система згенерує виключну ситуацію.
Якщо в описі операції (методу) вказано “проміжна операція“, то це означає, що створюється (продукується) новий потік даних, який може оброблятись далі в конвеєрному режимі. Конвеєрний режим передбачає подальше використання проміжних або кінцевих операцій над новоствореним потоком. У цьому випадку кінцева операція викликається останньою.
⇑
2. Кінцева операція. Приклад
У прикладі демонструється виконання кінцевих операцій.
Умова задачі. Обчислити мінімальне та максимальне значення у наборі випадкових чисел типу Double.
Текст демонстраційної програми наступний.
import java.util.ArrayList; import java.util.Optional; import java.util.stream.*; public class StreamAPI { public static void main(String[] args) { // Конвертувати в масив Double[] потік чисел // 1. Оголосити набір чисел у вигляді колекції ArrayList<Double> AL = new ArrayList<Double>(); // 2. Заповнити набір чисел випадковими значеннями for (int i=0; i<10; i++) AL.add((Math.random()*10)); // 3. Створити потік чисел Stream<Double> stream = AL.stream(); // 4. Знайти максимальне значення в масиві Optional<Double> max = stream.max(Double::compare); System.out.println("max = " + max.get()); // 5. Спроба виклику ще однієї операції - пошук мінімуму stream = AL.stream(); // Обов'язково потрібно створити новий потік Optional<Double> min = stream.min(Double::compare); System.out.println("min = " + min.get()); } }
У вищенаведеному коді спочатку виконується пошук максимуму, потім виконується пошук мінімуму. Операція пошуку максимуму
stream.max(Double::compare);
є кінцевою. Це означає, що після її виконання потік вважається спожитим. Спожитий потік неможливо далі обробляти. Якщо після пошуку максимуму забрати рядок
stream = AL.stream();
то після запуску на виконання програма згенерує виключення IllegalStateException.
Результат роботи програми
max = 8.627680677435304 min = 1.4456409633880085
⇑
3. Проміжна операція. Приклад
У прикладі демонструється виконання проміжної операції, яка сортує потік чисел у порядку спадання.
import java.util.*; import java.util.function.*; import java.util.stream.*; public class StreamAPI { public static void main(String[] args) { // Сортування потоку чисел у порядку спадання значень // 1. Створити набір чисел ArrayList<Integer> AL = new ArrayList<Integer>(); for (int i=0; i<10; i++) AL.add((int)(Math.random()*10)); System.out.println("AL = " + AL); // 2. Створити потік чисел на основі колекції AL Stream<Integer> stream = AL.stream(); // 3. Викликати проміжну операцію сортування - створюється новий потік. // 3.1. Створити метод порівняння Comparator<Integer> comparator = (a, b) -> b-a; // 3.2. Створити новий посортований потік - це є проміжна операція, // після неї потік можна далі обробляти Stream<Integer> sortStream = stream.sorted(comparator); // 3.3. Вивести новий потік System.out.print("sorted AL = "); // 3.3.1. Створити дію, яка виводить елемент потоку на екран Consumer<Integer> action; action = (n) -> { System.out.print(n + " "); }; // Передати дію action в метод forEach() для поелементної обробки sortStream.forEach(action); // forEach() - кінцева операція } }
У вищенаведеному коді створюється потік чисел stream з колекції AL. Отриманий потік сортується проміжною операцією sorted(). Метод sorted() утворює новий посортований потік.
Stream<Integer> sortStream = stream.sorted(comparator);
Оскільки sorted() є проміжною операцією, то новостворений потік далі можна обробляти. У нашому випадку здійснюється поелементний вивід усього потоку з допомогою методу forEach() як показано нижче
sortStream.forEach(action); // forEach() - кінцева операція
Метод forEach() є кінцевою операцією. Це означає, що потік sortStream спожито. Щоб використати потік заново, його потрібно відновити з джерела – набору чисел AL.
Після виконання програма видасть наступний результат
AL = [5, 4, 0, 5, 2, 9, 1, 3, 0, 2] sorted AL = 9 5 5 4 3 2 2 1 0 0
⇑
4. Формування нових потоків даних з допомогою конвеєру. Приклад
Умова задачі. Задано потік чисел. Знайти мінімальне з чисел потоку, які більше 5 і менше 20.
Розв’язок. Для розв’язку задачі потрібно використати підхід конвеєра для модифікації потоку. Використовуються дві операції (методи):
- операція (метод) filter() – проміжна операція;
- операція (метод) min() – кінцева операція.
Текст розв’язку задачі наступний
import java.util.*; import java.util.function.*; import java.util.stream.*; public class StreamAPI { public static void main(String[] args) { // Задача. Задано потік чисел. Знайти мінімальне з чисел потоку, які // більше 5 і менше 20. // 1. Створити набір чисел ArrayList<Integer> AL = new ArrayList<Integer>(); AL.add(15); AL.add(13); AL.add(7); AL.add(1); AL.add(23); AL.add(6); AL.add(3); AL.add(11); AL.add(22); AL.add(2); // 2. Створити потік чисел на основі колекції AL Stream<Integer> stream = AL.stream(); System.out.println("AL = " + AL); // 3. Викликати проміжну операцію фільтрування - створюється новий потік. // 3.1. Створити метод порівняння - числа, які більше за 5 Predicate<Integer> predicate = (a) -> a>5; // предикат (умова) // 3.2. Створити новий відфільтрований потік - це є проміжна операція, // після неї потік можна далі обробляти Stream<Integer> filteredStream = stream.filter(predicate); // 4. Викликати ще одну проміжну операцію фільтрування - створюється новий потік // Цього разу фільтруються числа, які менше 20. predicate = (a) -> a<20; // 5. Відфільтрувати той самий потік ще раз filteredStream = filteredStream.filter(predicate); // це знову проміжна операція // 6. Знайти мінімальне значення у новоствореному потоці Optional<Integer> min = filteredStream.min(Integer::compare); // це є кінцева операція // 7. Вивести мінімальне значення на екран System.out.println("min = " + min.get()); } }
Після виконання програма видасть наступний результат
AL = [15, 13, 7, 1, 23, 6, 3, 11, 22, 2] min = 6
⇑
5. Приклади отримання (відкриття) потоку даних. Методи stream(), parallelStream()
Приклад реалізує отримання потоку даних з різних видів колекцій. Для отримання послідовного потоку використовується метод stream(). Для отримання паралельного потоку використовується метод parallelStream().
import java.util.*; import java.util.stream.*; public class StreamAPI { public static void main(String[] args) { // Задача. Задано набір чисел. З цього набору створити потік // 1. Створити потік даних з колекції типу ArrayList<T> // 1.1. Створити колекцію чисел ArrayList<Integer> AL = new ArrayList<Integer>(); AL.add(15); AL.add(13); AL.add(7); AL.add(1); AL.add(23); AL.add(6); AL.add(3); AL.add(11); AL.add(22); AL.add(2); // 1.2. Створити послідовний потік даних на основі колекції AL Stream<Integer> stream = AL.stream(); // 1.3. Створити паралельний потік даних з колекції AL Stream<Integer> parallelStream = AL.parallelStream(); // 2. Створити потік даних з масиву цілих чисел int[] AI = { 2, 5, 4, 8, -1, 3, 9 }; IntStream streamInt = Arrays.stream(AI); // послідовний потік IntStream parallelStreamInt = streamInt.parallel(); // паралельний потік // 3. Створити потік даних з масиву дійсних чисел double[] AD = { 0.5, -1.8, 3.77, 4.23, 21.7, -10.8 }; DoubleStream streamDouble = Arrays.stream(AD); // послідовний потік до даного DoubleStream parallelStreamDouble = streamDouble.parallel(); // паралельний потік // 4. Створити потік даних з масиву типу long Long[] ALong = { 282039l, 3239290l, 23902309l, 72083289L }; Stream<Long> streamLong = Arrays.stream(ALong); // послідовний потік Stream<Long> parallelStreamLong = streamLong.parallel(); // паралельний потік } }
⇑
Зв’язані теми
⇑