1. Список методів типу Stream
Клас Stream
було створено для того, щоб можна було легко конструювати ланцюжки потоків даних. Для цього об'єкт типу Stream<T>
має методи, що повертають нові об'єкти типу Stream
.
Кожен із цих потоків даних уміє виконувати одну просту дію, натомість, якщо їх об'єднати в ланцюжки та ще й додати до цього таку цікаву річ, як лямбда-функції, на виході можна отримати дуже потужний інструмент. Незабаром ви самі в цьому переконаєтеся.
Отакі методи має клас Stream
(наводимо лише основні):
Методи | Опис |
---|---|
|
Створює потік з набору об'єктів |
|
Генерує потік за встановленим правилом |
|
З'єднує кілька потоків |
|
Фільтрує дані: пропускає тільки дані, що відповідають встановленому правилу |
|
Видаляє дублікати: не пропускає дані, що вже були |
|
Сортує дані |
|
Виконує дію над кожним елементом даних |
|
Обрізає дані після досягнення ліміту |
|
Пропускає перші n елементів даних |
|
Перетворює дані з одного типу на інший |
|
Перетворює дані з одного типу на інший |
|
Перевіряє, чи є серед елементів даних потоку щонайменше один, який відповідає встановленому правилу |
|
Перевіряє, чи всі дані в потоці відповідають установленому правилу |
|
Перевіряє, чи жоден елемент даних у потоці не відповідає встановленому правилу |
|
Повертає перший знайдений елемент, який відповідає правилу |
|
Повертає з потоку будь-який елемент, який відповідає правилу |
|
Шукає найменший елемент у потоці даних |
|
Повертає найбільший елемент у потоці даних |
|
Повертає кількість елементів у потоці даних |
|
Зчитує всі дані з потоку й повертає їх у вигляді колекції |
2. Створення потоків
Серед методів класу Stream
є три, котрі ми ще не розглянули. Завдання цих трьох методів — створювати нові потоки.
Метод Stream<T>.of(T obj)
Метод of()
створює потік, який складається з одного елемента. Зазвичай це потрібно, коли, припустімо, функція отримує як параметр об'єкт типу Stream<T>
, а у вас є тільки об'єкт типу T
. Тоді ви можете легко й просто за допомогою методу of()
отримати потік, який складається з одного елемента.
Приклад:
Stream<Integer> stream = Stream.of(1);
Метод Stream<T> Stream.of(T obj1, T obj2, T obj3, …)
Метод of()
створює потік, який складається з переданих елементів. Кількість елементів може бути будь-якою. Приклад:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Метод Stream<T> Stream.generate(Supplier<T> obj)
Метод generate()
дає змогу встановити правило, за яким генеруватиметься черговий елемент потоку під час запиту цього елемента. Наприклад, можна щоразу віддавати випадкове число.
Приклад:
Stream<Double> s = Stream.generate(Math::random);
Метод Stream<T> Stream.concat(Stream<T> a, Stream<T> b)
Метод concat()
з'єднує два передані потоки в один. Під час читання даних спочатку буде прочитано дані з першого потоку, а потім із другого. Приклад:
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream2 = Stream.of(10, 11, 12, 13, 14);
Stream<Integer> result = Stream.concat(stream1, stream2);
3. Фільтрування даних
Ще 6 методів створюють нові потоки даних, які дають змогу з'єднувати потоки в ланцюжки різної складності.
Метод Stream<T> filter(Predicate<T>)
Цей метод повертає новий потік даних, який фільтрує дані з потоку-джерела згідно з переданим правилом. Метод потрібно викликати для об'єкта типу Stream<T>
.
Для встановлення правила фільтрування можна використовувати лямбда-функцію, яку компілятор потім перетворить на об'єкт типу Predicate<T>
.
Приклади:
Ланцюжки потоків | Пояснення |
---|---|
|
Залишаємо тільки числа, менші за 3 |
|
Залишаємо тільки числа, більші за нуль |
Метод Stream<T> sorted(Comparator<T>)
Цей метод повертає новий потік даних, який сортує дані з потоку-джерела. Як параметр можна передати компаратор, який буде встановлювати правила порівняння двох елементів потоку даних.
Метод Stream<T> distinct()
Цей метод повертає новий потік даних, який містить лише унікальні дані з потоку даних джерела. Усі дублікати даних відкидаються. Приклад:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 2, 2, 2, 3, 4);
Stream<Integer> stream2 = stream.distinct(); // 1, 2, 3, 4, 5
Метод Stream<T> peek(Consumer<T>)
Цей метод повертає новий потік даних, хоча дані в ньому ті самі, що й у потоці-джерелі. Однак під час запиту чергового елемента з потоку для цього елемента викликається функція, яку ви передали в метод peek()
.
Якщо в метод peek()
передати функцію system.out::println
, тоді всі об'єкти виводитимуться на екран у той момент, коли вони проходитимуть через потік.
Метод Stream<T> limit(int n)
Цей метод повертає новий потік даних, який містить лише перші n
елементів даних з потоку даних джерела. Решта даних відкидається. Приклад:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 2, 2, 2, 3, 4);
Stream<Integer> stream2 = stream.limit(3); // 1, 2, 3
Метод Stream<T> skip(int n)
Цей метод повертає новий потік даних, який містить усі ті самі дані, що й потік-джерело, але пропускає (ігнорує) перші n
елементів даних. Приклад:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 2, 2, 2, 3, 4);
Stream<Integer> stream2 = stream.skip(3); // 4, 5, 2, 2, 2, 3, 4