JavaRush/Курсы/Java Syntax Pro/Работа с потоками, часть 3

Работа с потоками, часть 3

Открыта

1. Проверка

Думаю, вам уже скучно изучать, как конструировать цепочки потоков данных. Хочется наконец-то с этими данными что-то делать.

У класса Stream есть три стандартных метода, которые не конструируют потоки, а проверяют, что за данные находятся в этих потоках. Это методы: anyMatch(), allMatch() и noneMatch().

Метод boolean anyMatch(правило)

Этот метод проверяет, что в потоке есть хотя бы один элемент, который удовлетворяет правилу, которое передается в метод. Если такой элемент есть, метод возвращает true, иначе — false.

Примеры

Код Примечание
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
boolean result = stream.anyMatch(x -> x > 0);

true
Stream<Integer> stream = Stream.of(1, -2, 3, -4, 5);
boolean result = stream.anyMatch(x -> x > 0);

true
Stream<Integer> stream = Stream.of(1, -2, 3, -4, 5);
boolean result = stream.filter(x -> x < 0).anyMatch(x -> x > 0);

false

В последнем примере мы сначала отфильтровываем (пропускаем через фильтр) все элементы меньше нуля, а затем уже среди них проводим проверку, есть ли хотя бы один элемент больше нуля. Ясное дело, таких элементов там уже нет.

Метод boolean allMatch(правило)

Этот метод проверяет, что все элементы в потоке соответствуют правилу. Правило передается в метод в качестве параметра:

Код Примечание
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
boolean result = stream.allMatch(x -> x > 0);
true
(все элементы больше нуля)
Stream<Integer> stream = Stream.of(1, -2, 3, -4, 5);
boolean result = stream.allMatch(x -> x > 0);
false
(есть элементы меньше или равны нулю)
Stream<Integer> stream = Stream.of(1, -2, 3, -4, 5);
boolean result = stream.filter(x -> x < 0).allMatch(x -> x < 0);
true
(отфильтровали элементы меньше нуля)

В последнем примере мы сначала пропускаем через фильтр только элементы меньше нуля, а потом уже среди них выполняем проверку, что все элементы меньше нуля. Проверка проходит успешно.

Метод boolean noneMatch(правило)

Метод noneMatch() проверяет, что в потоке нет ни одного элемента, который соответствует переданному правилу. Противоположный по смыслу метод к методу allMatch().

Код Примечание
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
boolean result = stream.noneMatch(x -> x > 0);

false
Stream<Integer> stream = Stream.of(1, -2, 3, -4, 5);
boolean result = stream.noneMatch(x -> x > 0);

false
Stream<Integer> stream = Stream.of(1, -2, 3, -4, 5);
boolean result = stream.filter(x -> x < 0).noneMatch(x -> x > 0);

true


2. Служебные классы: класс Optional

Иногда программистам очень неудобно работать с ссылками на null. Например, вы сравниваете две строки. Если обе переменные не null, тогда можно просто вызвать s1.equals(s2), и все будет работать. А вот если s1 может быть null, придется писать код, который учитывает эту ситуацию, чтобы не возникло NullPointerException.

Поэтому программисты придумали служебный класс Optional<T>. Выглядит его код примерно так:

Код Примечание
class Optional<Tип>
{
   private final Tип value;
   private Optional() { this.value = null;}
   private Optional(value) { this.value = value;}
   public static <Tип> Optional<Tип> of(Tип value)
   {
      return new Optional<Tип>(value);
   }

   public boolean isPresent()
   {
      return value != null;
   }

   public boolean isEmpty()
   {
      return value == null;
   }

   public Tип get()
   {
      if (value == null)
      {
         throw new NoSuchElementException();
      }
      return value;
   }

   public Tип orElse(Tип other)
   {
      return value != null ? value : other;
   }

   public Tип orElseThrow()
   {
      if (value == null)
      {
         throw new NoSuchElementException();
      }
      return value;
   }
}










Проверяет, что внутри находится значение (ссылка не null)



Проверяет, что объект хранит ссылку на null




Возвращает значение, которое хранит. Кидает исключение, если значения нет.







Возвращает значение, или если внутри хранится null, то переданное в метод второе значение



Возвращает значение или кидает исключение, если значения нет.

Цель этого класса – просто хранить в себе объект T (ссылку на объект типа T). Ссылка на объект внутри класса Optional<T> может быть null.

Этот класс позволяет писать программистам код немного красивее. Сравните:

С использованием Optional Без использования Optional
public void printString(String s)
{
   Optional<String> str = Optional.ofNullable(s);
   System.out.println(str.orElse(""));
}
public void printString(String s)
{
   String str = s != null ? s : "";
   System.out.println(str)
}

Один объект 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(). Если программист знает, что реально через все фильтры пройдет 0 или 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();
Комментарии (313)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Euraks Backend Developer
9 октября, 04:34
🦔
Grigoryvvv
Уровень 28
Expert
31 июля, 14:49
31.07.2026 / 19 уровень
SUNSHINE
Уровень 30
26 марта, 19:54
Открывайте окна, сейчас будет душно) Первая задача) Из названия метода(т.к. подсказки компилятора аналогично содержат логическую ошибку), следует проверка на то, чтобы все данные в потоке были отрицательными числами. Но как валидатор, так и верное решение в валидаторе упускают один маленький момент, об который человечество спотыкалась всю свою историю - они упускают число 0 ;)
YoungDV Java Developer
19 сентября 2025, 20:36
Метод Optional<T> findFirst() Метод findFirst() просто возвращает первый элемент из потока и все — на этом его работа завершается. Более интересно, что метод возвращает не объект типа T, а обертку над ним — объект типа Optional<T>. Это сделано для того, чтобы никогда не сталкиваться с ситуацией, когда метод не находит объект и возвращает null.
Exaltyr777
Уровень 25
13 августа 2025, 18:27
При параллельной обработке потоков может случиться такая ситуация, что в какой-то части потока элемент уже найден, но пока еще не понятно, будет он первым или нет. Эмм, а это как?
Exaltyr777
Уровень 25
13 августа 2025, 18:11
Я правильно понял Optional.get() и Optional.orElseThrow() - два одинаковых метода?
Закирка Джава МОНСТРШколяр в Школа
16 октября 2025, 12:58
ахаххаха походу
m1ffer_
Уровень 41
18 февраля, 08:09
Почему-то создатели курса решили не отмечать тот факт, что есть перегруженная версия метода, в которую передается лямбда-выражение, в котором прописывается какое исключение выбросить
Anonymous #3585174
Уровень 33
24 июля 2025, 10:35
Like
VadChet
Уровень 29
22 мая 2025, 04:36
Думаю, методы Match можно перевести как: anyMatch - кто-нибудь, allMatch - все, noneMatch - никого. Тогда получается: anyMatch(x -> x > 0) - "кто-нибудь больше 0?" да/нет; allMatch(x -> x > 0) - "все больше 0?" да/нет; noneMatch(x -> x > 0) - "никого больше 0?" да/нет; Тогда становится понятно, если все числа отрицательные, то, да, никого больше 0 (true).
Andrey Ku
Уровень 2
Expert
18 марта 2025, 06:00
Почему не сделать эти темы отдельно ? Огромный урок тяжело проходить. И если можно то я внесу свое предложение, делить уроки на время, которое требуется на его прохождение, просто один урок можно пройти за 10 минут и все а над вторым торчишь 2 часа, отсюда демотивация и нет подкрепляющего действия, что я что-то сделал и закончил, наоборот не хочется возвращаться к этому огромному уроку. Например тему про Optional я бы вынес в отдельный урок, мы изучаем stream тут вроде уже все понятно, потом бах и новая тема внутри урока и еще сложная. И потом опять про stream как буд-то автор копировал уроки и случайно впихнул сюда про Optional
я на одной задаче торчал два часа))) а на каком то уровне раннее помню часов 8 решал одну задачу, но в итоге решил и разобрался, остальные задачки с того же уровня решил просто как на печатной машинке набрав код за 1 минуту
Zhenyok Avramenko
Уровень 30
27 января, 13:05
пришлось докуменатцию рыть
Cryptosin Crypto Magnat
7 марта 2025, 13:36
Что такое Optional простыми словами? Представь, что ты открываешь коробку с подарком. Внутри может быть что-то ценное, а может быть пусто. Optional<T> — это такая коробка в Java: Если в коробке есть что-то → можно открыть и достать. Если коробка пустая → безопасно узнаем об этом, не наткнувшись на ошибку. Обычно в Java, если переменная равна null, а мы пытаемся с ней работать, программа ломается с ошибкой NullPointerException. Optional помогает избежать этого. 🎁 Как создать Optional 1. Коробка с подарком (Optional с данными)
Optional<String> коробка = Optional.of("Привет!");
Это значит, что в коробке лежит строка "Привет!". 2. Пустая коробка (Optional без данных)
Optional<String> пустаяКоробка = Optional.empty();
Здесь коробка пустая, в ней ничего нет. 3. Коробка, которая может быть пустой (Optional.ofNullable())
Optional<String> коробка = Optional.ofNullable(null);
Если переданный объект не null, коробка его сохранит. Если null, коробка будет пустой. 📦 Как достать значение из Optional? Допустим, у нас есть коробка:
Optional<String> коробка = Optional.of("Сюрприз!");
1. Открываем коробку, если в ней что-то есть
if (коробка.isPresent()) { // Проверяем, не пустая ли коробка
    System.out.println(коробка.get()); // Достаём значение
}
Но get() опасен, если коробка вдруг окажется пустой. Лучше использовать безопасные способы: 2. Используем ifPresent()
коробка.ifPresent(System.out::println);
Если в коробке есть что-то, оно будет выведено. Если пусто — ничего не произойдёт.
Cryptosin Crypto Magnat
7 марта 2025, 13:38
3. Указываем запасной вариант (orElse)
String подарок = коробка.orElse("Коробка оказалась пустой!");
System.out.println(подарок);
Если в коробке что-то было, программа его достанет. Если пусто — получим "Коробка оказалась пустой!". 4. Запасной вариант с расчетом (orElseGet)
String подарок = коробка.orElseGet(() -> "Запасной подарок!");
Разница между orElse() и orElseGet() в том, что orElse() сразу вычисляет запасной вариант, даже если он не понадобится. orElseGet() сделает это только если коробка пуста. 5. Выбросить ошибку, если коробка пустая (orElseThrow)
String подарок = коробка.orElseThrow(() -> new RuntimeException("А где мой подарок?"));
Если Optional пустой, программа выдаст ошибку. 🔄 Преобразование значений (map и flatMap) Представь, что в коробке лежит слово "Java", а мы хотим узнать его длину:
Optional<String> коробка = Optional.of("Java");
Optional<Integer> длина = коробка.map(String::length);
длина.ifPresent(System.out::println); // Выведет: 4
Метод map() позволяет изменить содержимое коробки. 🎛 Фильтрация значений (filter) Допустим, у нас в коробке лежит "Java", а мы хотим оставить только слова длиннее 5 символов:
Optional<String> коробка = Optional.of("Java");
Optional<String> длинноеСлово = коробка.filter(s -> s.length() > 5);
System.out.println(длинноеСлово.orElse("Слово слишком короткое")); // Выведет: "Слово слишком короткое"
Cryptosin Crypto Magnat
7 марта 2025, 13:38
❌ Где Optional НЕ нужно? В переменных класса (иначе будет путаница). В параметрах метода (null проще проверить с if). Когда он не даёт пользы (например, если значение точно не будет null). 🏁 Итог Optional — это безопасная коробка для значений. Можно проверить, пустая она или нет, без null. Можно достать значение (orElse, get(), ifPresent). Можно преобразовывать (map, flatMap). Можно фильтровать (filter). Optional избавляет от NullPointerException и делает код чище! 🚀
Anonymous #3312942
Уровень 32
15 июля 2025, 20:11
Пожалуйста, побольше ваших комментариев к лекциям, они бесподобны!