1. Список методів типу Stream

Клас Stream було створено для того, щоб можна було легко конструювати ланцюжки потоків даних. Для цього об'єкт типу Stream<T> має методи, що повертають нові об'єкти типу Stream.

Кожен із цих потоків даних уміє виконувати одну просту дію, натомість, якщо їх об'єднати в ланцюжки та ще й додати до цього таку цікаву річ, як лямбда-функції, на виході можна отримати дуже потужний інструмент. Незабаром ви самі в цьому переконаєтеся.

Отакі методи має клас Stream (наводимо лише основні):

Методи Опис
Stream<T> of()
Створює потік з набору об'єктів
Stream<T> generate()
Генерує потік за встановленим правилом
Stream<T> concat()
З'єднує кілька потоків
Stream<T> filter()
Фільтрує дані: пропускає тільки дані, що відповідають встановленому правилу
Stream<T> distinct()
Видаляє дублікати: не пропускає дані, що вже були
Stream<T> sorted()
Сортує дані
Stream<T> peek()
Виконує дію над кожним елементом даних
Stream<T> limit(n)
Обрізає дані після досягнення ліміту
Stream<T> skip(n)
Пропускає перші n елементів даних
Stream<R> map()
Перетворює дані з одного типу на інший
Stream<R> flatMap()
Перетворює дані з одного типу на інший
boolean anyMatch()
Перевіряє, чи є серед елементів даних потоку щонайменше один, який відповідає встановленому правилу
boolean allMatch()
Перевіряє, чи всі дані в потоці відповідають установленому правилу
boolean noneMatch()
Перевіряє, чи жоден елемент даних у потоці не відповідає встановленому правилу
Optional<T> findFirst()
Повертає перший знайдений елемент, який відповідає правилу
Optional<T> findAny()
Повертає з потоку будь-який елемент, який відповідає правилу
Optional<T> min()
Шукає найменший елемент у потоці даних
Optional<T> max()
Повертає найбільший елемент у потоці даних
long count()
Повертає кількість елементів у потоці даних
R collect()
Зчитує всі дані з потоку й повертає їх у вигляді колекції

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>.

Приклади:

Ланцюжки потоків Пояснення
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream2 = stream.filter(x -> (x < 3));

Залишаємо тільки числа, менші за 3
Stream<Integer> stream = Stream.of(1, -2, 3, -4, 5);
Stream<Integer> stream2 = stream.filter(x -> (x > 0));

Залишаємо тільки числа, більші за нуль

Метод 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

4
Задача
Java Core,  6 рівень3 лекція
Недоступна
My first thread
My first thread
4
Задача
Java Core,  6 рівень3 лекція
Недоступна
My second thread
My second thread
9
Задача
Java Core,  6 рівень3 лекція
Недоступна
Список та потоки
Список та потоки