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

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

Java Syntax Pro
18 уровень , 5 лекция
Открыта

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();
Комментарии (316)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
YoungDV Уровень 22
19 сентября 2025
Метод Optional<T> findFirst() Метод findFirst() просто возвращает первый элемент из потока и все — на этом его работа завершается. Более интересно, что метод возвращает не объект типа T, а обертку над ним — объект типа Optional<T>. Это сделано для того, чтобы никогда не сталкиваться с ситуацией, когда метод не находит объект и возвращает null.
Exaltyr777 Уровень 25
13 августа 2025
При параллельной обработке потоков может случиться такая ситуация, что в какой-то части потока элемент уже найден, но пока еще не понятно, будет он первым или нет. Эмм, а это как?
Exaltyr777 Уровень 25
13 августа 2025
Я правильно понял Optional.get() и Optional.orElseThrow() - два одинаковых метода?
16 октября 2025
ахаххаха походу
Anonymous #3585174 Уровень 33
24 июля 2025
Like
VadChet Уровень 29
22 мая 2025
Думаю, методы 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
Почему не сделать эти темы отдельно ? Огромный урок тяжело проходить. И если можно то я внесу свое предложение, делить уроки на время, которое требуется на его прохождение, просто один урок можно пройти за 10 минут и все а над вторым торчишь 2 часа, отсюда демотивация и нет подкрепляющего действия, что я что-то сделал и закончил, наоборот не хочется возвращаться к этому огромному уроку. Например тему про Optional я бы вынес в отдельный урок, мы изучаем stream тут вроде уже все понятно, потом бах и новая тема внутри урока и еще сложная. И потом опять про stream как буд-то автор копировал уроки и случайно впихнул сюда про Optional
Евгений Уровень 37
29 марта 2025
я на одной задаче торчал два часа))) а на каком то уровне раннее помню часов 8 решал одну задачу, но в итоге решил и разобрался, остальные задачки с того же уровня решил просто как на печатной машинке набрав код за 1 минуту
Cryptosin Уровень 24
7 марта 2025
Что такое 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 Уровень 24
7 марта 2025
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 Уровень 24
7 марта 2025
❌ Где Optional НЕ нужно? В переменных класса (иначе будет путаница). В параметрах метода (null проще проверить с if). Когда он не даёт пользы (например, если значение точно не будет null). 🏁 Итог Optional — это безопасная коробка для значений. Можно проверить, пустая она или нет, без null. Можно достать значение (orElse, get(), ifPresent). Можно преобразовывать (map, flatMap). Можно фильтровать (filter). Optional избавляет от NullPointerException и делает код чище! 🚀
Anonymous #3312942 Уровень 32
15 июля 2025
Пожалуйста, побольше ваших комментариев к лекциям, они бесподобны!
S(Anonymous #3313184) Уровень 27
5 марта 2025
в задаче с дорогим автомобилем в строке кода 1. «… Optional<Car> moreExpensiveCar = mostExpensiveCar.flatMap(car -> getMoreExpensiveCar(bmw, car)); …» аргумент «bmw» в задаче объявлен и тип его – поток а вот аргумент «car» нигде не объявлен (или я не прав?), хотя по логике именно на место «car» должен вкладываться аргумент mostExpensiveCar с типом «Car»(или Optional<Car>?), поэтому в сигнатуре метода: public static Optional<Car> getMoreExpensiveCar(Stream<Car> cars, Car mostExpensiveCar) второй параметр «Car mostExpensiveCar» с типом «Car» по идее должен был быть прописан так: «Car car» и в то же время mostExpensiveCar имеет тип Optional<Car>, поэтому надо было бы к mostExpensiveCar применять метод get(), чтобы получить «очищенный от обертки optional» car – объект типа Car. Если кто поймет дайте знать, благодарю! 2. + в задаче появляется метод «flatMap» класса Optional<>, о чем не повествовалось…
Юрий Уровень 20
27 февраля 2025
Надо покущац
Victor Уровень 36
15 февраля 2025
Не хватает ещё двух задач: Первая более дешёвая машина (из 1 списка) чем самая дорогая машина (из второго списка) и первая более дорогая (из 1-го) чем самая дешёвая из второго.