1. Перевірка
Напевно, вам уже нудно вивчати, як конструювати ланцюжки потоків даних. Хочеться нарешті з цими даними щось робити.
Клас Stream
має три стандартних методи, які не конструюють потоки, а перевіряють, які дані містяться в цих потоках. Це методи anyMatch()
, allMatch()
і noneMatch()
.
Метод boolean anyMatch(правило)
Цей метод перевіряє, чи є в потоці щонайменше один елемент, який відповідає правилу, переданому в метод. Якщо такий елемент є, метод повертає true
, інакше — false
.
Приклади
Код | Примітка |
---|---|
|
|
|
|
|
|
В останньому прикладі ми спочатку відфільтровуємо (пропускаємо крізь фільтр) усі елементи, менші за нуль, а потім уже серед них виконуємо перевірку, чи є принаймні один елемент, більший за нуль. Ясна річ, таких елементів там уже немає.
Метод boolean allMatch(правило)
Цей метод перевіряє, чи всі елементи в потоці відповідають правилу. Правило передається в метод як параметр:
Код | Примітка |
---|---|
|
(усі елементи більші за нуль)
|
|
(є елементи, менші або рівні нулю)
|
|
(відфільтрували елементи, менші за нуль)
|
В останньому прикладі ми спочатку пропускаємо крізь фільтр тільки елементи, менші за нуль, а потім уже серед них виконуємо перевірку, чи всі вони менші за нуль. Перевірка проходить успішно.
Метод boolean noneMatch(правило)
Метод noneMatch()
перевіряє, чи в потоці немає жодного елемента, що відповідає переданому правилу. Метод, протилежний за змістом до методу anyMatch()
.
Код | Примітка |
---|---|
|
|
|
|
|
|
2. Службові класи: клас Optional
Іноді програмістам дуже незручно працювати з посиланнями на null
. Приміром, ви порівнюєте два рядки. Якщо обидві змінні не null
, тоді можна просто викликати s1.equals(s2)
, і все працюватиме. А от якщо s1
може бути null
, доведеться писати код, який враховує цю ситуацію, щоб не виник NullPointerException
.
Тому програмісти придумали службовий клас Optional<T>
. Його код має приблизно такий вигляд:
Код | Примітка |
---|---|
|
Перевіряє, чи всередині є значення (посилання не є null ) Перевіряє, чи зберігає об'єкт посилання на null Повертає значення, яке зберігає. Кидає виняток, якщо значення немає. Повертає значення або, якщо всередині зберігається null , то передане в метод друге значення Повертає значення або кидає виняток, якщо значення немає. |
Призначення цього класу — просто зберігати в собі об'єкт T (посилання на об'єкт типу T). Посилання на об'єкт всередині класу Optional<T>
може бути null
.
Цей клас дає програмістам змогу писати красивіший код. Порівняйте:
З використанням Optional | Без використання Optional |
---|---|
|
|
Один об'єкт Optional
завжди можна порівняти з іншим об'єктом Optional
за допомогою методу equals
, навіть якщо вони зберігають у собі посилання на null
.
У загальних рисах клас Optional уможливлює «красивіший» запис перевірки на null
і дій у разі, якщо всередині об'єкта Optional
зберігається null
.
3. Пошук елементів
Повернімося до класу Stream
. Клас Stream
має ще 4 методи, що дають змогу шукати елементи в потоці. Це методи findFirst()
, findAny()
, min()
і max()
.
Метод Optional<T> findFirst()
Метод findFirst()
просто повертає перший елемент із потоку, і все — на цьому його робота завершується.
Цікаво, що метод повертає не об'єкт типу T
, а обгортку над ним — об'єкт типу Optional<T>
. Це зроблено для того, щоб ніколи не стикатися із ситуацією, коли метод не знаходить об'єкт і повертає null
.
Приклад:
ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Привіт", "як", "справи?");
String str = list.stream().findFirst().get(); // Привіт
Для кращого розуміння запишімо останній рядок у кілька рядків:
ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Привіт", "як", "справи?");
Stream<String> stream = list.stream();
Optional<String> result = stream.findFirst();
String str = result.get(); // Привіт
Останній метод get()
— це просто витягання значення, що зберігається всередині об'єкта Optional
.
Метод Optional<T> findAny()
Метод findAny()
повертає будь-який елемент з потоку й на цьому завершується. Цей метод — аналог методу findFirst()
, тільки для потоків, які обробляються паралельно.
Під час паралельної обробки потоків може трапитися така ситуація, що в якійсь частині потоку елемент уже знайдено, але поки ще не зрозуміло, буде він першим чи ні.
Якщо елементів, які пройшли всі фільтри, багато, а програмісту важливо отримати саме найперший із них, слід викликати метод findFirst()
. Якщо програміст знає, що реально крізь усі фільтри пройде щонайбільше 1 елемент, тоді досить просто викликати findAny()
— так буде швидше.
Метод Optional<T> min(Comparator<T>)
Метод min()
порівнює всі елементи потоку за допомогою об'єкта comparator
і повертає мінімальний елемент. Найзручніше задати об'єкт-компаратор за допомогою лямбда-функції.
Приклад — пошук рядка мінімальної довжини:
ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Привіт", "як", "справи?");
String min = list.stream().min( (s1, s2)-> s1.length()-s2.length() ).get();
Метод Optional<T> max(Comparator<T>)
Метод max()
порівнює всі елементи потоку за допомогою об'єкта comparator
і повертає максимальний елемент. Найзручніше задати об'єкт-компаратор за допомогою лямбда-функції.
Приклад — пошук рядка максимальної довжини:
ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Привіт", "як", "справи?");
String max = list.stream().max( (s1, s2)-> s1.length()-s2.length() ).get();