Stream.allMatch: примеры (JAVA)

Обзор метода allMatch для потоков Java
Раздел: Потоки данных (Stream API) - терминальные операции
Stream.allMatch(Predicate predicate): boolean

Описание метода allMatch

Метод allMatch принадлежит интерфейсу java.util.stream.Stream и является конечной операцией, проверяющей, удовлетворяют ли все элементы потока заданному предикату. Сигнатура метода:

boolean allMatch(Predicate<? super T> predicate)

Краткое поведение:

  • Возвращает true, если для каждого элемента потока предикат возвращает true.
  • Если поток пустой, возвращает true (истина для всех элементов пустого множества).
  • Операция может завершиться досрочно (short-circuit): при обнаружении первого элемента, для которого предикат возвращает false, вычисление прекращается и возвращается false.
  • В случае использования параллельного потока проверка также может быть досрочной, но порядок и момент осуществления проверок зависят от реализации параллельного выполнения.

Аргументы и возвращаемое значение:

  • predicate - объект типа java.util.function.Predicate<? super T>. Не допускается null; при передаче null выбрасывается NullPointerException.
  • Возвращаемое значение - булево (boolean): true или false в соответствии с описанным поведением.

Дополнительные замечания:

  • Все исключения, возникающие в предикате, пробрасываются наружу и прерывают выполнение.
  • При использовании параллельного потока следует избегать побочных эффектов и состояния, разделяемого между потоками, в предикате.
  • Для примитивных потоков существуют специализированные версии: IntStream.allMatch, LongStream.allMatch, DoubleStream.allMatch.

Примеры использования allMatch

Короткие иллюстрации типичных ситуаций.

1) Все элементы удовлетворяют условию

List<Integer> nums = List.of(2, 4, 6, 8);
boolean res = nums.stream().allMatch(n -> n % 2 == 0);
System.out.println(res);
true

2) Есть элемент, не удовлетворяющий предикату (досрочный возврат)

List<Integer> nums = List.of(2, 3, 6);
boolean res = nums.stream().allMatch(n -> n % 2 == 0);
System.out.println(res);
false

3) Пустой поток

List<String> empty = List.of();
boolean res = empty.stream().allMatch(s -> s.length() > 0);
System.out.println(res);
true

4) Параллельный поток: возможна досрочная остановка без гарантии порядка проверок

List<Integer> nums = Arrays.asList(1,2,3,4,5,6);
boolean res = nums.parallelStream().allMatch(n -> n < 100);
System.out.println(res);
true

Похожие методы в Java

Краткий обзор ближайших по смыслу операций и случаев применения.

  • anyMatch: возвращает true, если хотя бы для одного элемента предикат истинный. Предпочтительнее при поиске хотя бы одного совпадения.
  • noneMatch: возвращает true, если ни один элемент не удовлетворяет предикату. Эквивалент логического отрицания anyMatch.
  • filter + findFirst / findAny: при необходимости получить сам элемент вместо булева результата. Если важно получить первый подходящий элемент, лучше использовать filter(...).findFirst().
  • collect с агрегатором: если требуется более сложная агрегация или подробный отчет о нарушениях, используется Collectors и последующая обработка.
  • IntStream/LongStream/DoubleStream.allMatch: специализированные варианты для примитивов, дают меньшие накладные расходы на автоупаковку.

Эквиваленты в других языках

Краткие сравнения и отличия с примерами.

  • JavaScript: метод Array.prototype.every. Поведение очень похоже: пустой массив возвращает true, досрочная остановка при первом false. Пример:
const arr = [2,4,6];
console.log(arr.every(n => n % 2 === 0));
true
  • Python: встроенная функция all(). Ожидает итерируемый объект. Пример:
nums = [2,4,6]
print(all(n % 2 == 0 for n in nums))
True
  • C#: LINQ-метод Enumerable.All. Синтаксис и семантика близки к Java. Пример:
var nums = new[] {2,4,6};
Console.WriteLine(nums.All(n => n % 2 == 0));
True
  • Kotlin: функция расширения all для коллекций. Работает аналогично. Пример:
val nums = listOf(2,4,6)
println(nums.all { it % 2 == 0 })
true
  • Go: не имеет встроенной функции; используется явный цикл. Пример:
nums := []int{2,4,6}
all := true
for _, n := range nums {
    if n%2 != 0 { all = false; break }
}
fmt.Println(all)
true
  • PHP: нет прямого аналога в стандартной библиотеке; используется цикл или комбинация array_filter и сравнения длин. Пример короткий:
$nums = [2,4,6];
$all = true;
foreach ($nums as $n) { if ($n % 2 !== 0) { $all = false; break; } }
echo $all ? 'true' : 'false';
true
  • SQL: в ряде диалектов есть агрегат EVERY, либо используется NOT EXISTS с противоположным условием. Пример для PostgreSQL:
SELECT EVERY(val > 0) FROM (VALUES (1),(2),(-1)) AS t(val);
f

Отличия от Java: в большинстве языков смысл тот же, но особенности реализации параллелизма и типизация могут влиять на производительность и поведение при null/None/undefined.

Типичные ошибки при использовании allMatch

Список распространенных ошибок с примерами.

1) Передача null в качестве предиката

List<Integer> nums = List.of(1,2,3);
nums.stream().allMatch(null);
Exception in thread "main" java.lang.NullPointerException
    at java.base/java.util.Objects.requireNonNull(Objects.java:246)
    at java.base/java.util.stream.ReferencePipeline.allMatch(ReferencePipeline.java:...)
    ...

2) Предикат бросает исключение (оно пробрасывается наружу)

Stream.of("a", null, "c").allMatch(s -> s.length() > 0);
Exception in thread "main" java.lang.NullPointerException
    at ...

3) Использование состояние-зависимого предиката в параллельном потоке (гораздо более тонкие ошибки)

List<Integer> nums = IntStream.range(0,1000).boxed().collect(Collectors.toList());
AtomicInteger calls = new AtomicInteger();
boolean res = nums.parallelStream().allMatch(n -> calls.incrementAndGet() < 10);
System.out.println(res + ", calls=" + calls.get());
false, calls=someNumber (значение зависит от выполнения, непредсказуемо)

4) Ожидание детерминированного порядка проверок в параллельном режиме. Порядок может отличаться и влиять на производительность и количество вызовов предиката.

5) Применение к потенциально бесконечным потокам без условий, приводящим к быстрому false. Если предикат никогда не возвращает false, выполнение не завершится.

Изменения и история

Метод allMatch введен вместе с Streams API в Java 8 и с тех пор не претерпел изменений в сигнатуре. Для примитивных потоков поддержка была добавлена параллельно с соответствующими примитивными интерфейсами (IntStream, LongStream, DoubleStream).

Со временем улучшались оптимизации выполнения параллельных потоков в JVM, но контракт поведения метода остался прежним.

Расширенные и редкие сценарии применения

Несколько нестандартных и углубленных примеров с пояснениями.

1) Валидация структуры объектов с комбинированными условиями

Пример java
record Person(String name, int age) {}
List<Person> people = List.of(new Person("Ivan", 30), new Person("Anna", 25));
boolean allValid = people.stream().allMatch(p -> p.name() != null && !p.name().isBlank() && p.age() >= 18);
System.out.println(allValid);
true

Пояснение: удобно для проверки входных данных перед сохранением.

2) Применение с промежуточными операциями для ранней фильтрации

Пример java
boolean res = users.stream()
    .filter(u -> u.isActive())
    .map(User::getScore)
    .allMatch(score -> score >= 50);
System.out.println(res);
true или false в зависимости от данных

Пояснение: фильтрация уменьшает набор для проверки, что может улучшить производительность.

3) Использование с параллельным и неупорядоченным потоком для ускорения проверки

Пример java
boolean res = bigCollection.parallelStream().unordered().allMatch(predicate);
System.out.println(res);
true или false

Пояснение: вызов unordered() позволяет внутреннему механизму лучше распараллеливать работу при отсутствии значимости порядка.

4) Комбинация с короткоживущим исключением и логированием

Пример java
AtomicReference<Optional<String>> bad = new AtomicReference<>(Optional.empty());
boolean ok = values.stream().allMatch(v -> {
    try {
        return check(v);
    } catch(RuntimeException e) {
        bad.set(Optional.of(e.getMessage()));
        throw e;
    }
});
// если было исключение, оно уже проброшено наружу
(при исключении) Exception выбрасывается дальше, bad содержит сообщение

Пояснение: логирование деталей ошибки перед пробросом помогает в диагностике; при параллельном выполнении нужно учитывать конкурентный доступ к bad.

5) Проверка на соответствие регулярному выражению с использованием Pattern (без создания лишних объектов)

Пример java
Pattern p = Pattern.compile("^[A-Z]{3}-\\d{4}$");
boolean ok = codes.stream().allMatch(p.asPredicate());
System.out.println(ok);
true или false

6) Пример с бесконечным потоком, где ожидается досрочная остановка

Пример java
boolean res = Stream.iterate(0, n -> n + 1)
    .allMatch(n -> n < 1000); // вернёт false при достижении 1000, но для этого требуется пройти все числа до 1000
System.out.println(res);
false

Пояснение: для бесконечных потоков нужно иметь условие, приводящее к false или использовать ограничение limit.

7) Оптимизация подсчёта с ранним выходом вместо коллекционирования

Пример java
boolean allPositive = stream.peek(System.out::println)
    .allMatch(x -> x > 0);
System.out.println(allPositive);
(печать элементов до первого не положительного)\nfalse/true

Пояснение: применение peek помогает отладить, сколько элементов проверено до срабатывания short-circuit.

8) Специальный случай: использование в сочетании с Optional

Пример java
Optional<List<Integer>> maybeList = Optional.of(List.of(2,4,6));
boolean ok = maybeList.map(list -> list.stream().allMatch(n -> n % 2 == 0)).orElse(true);
System.out.println(ok);
true

Пояснение: если коллекция отсутствует, по контексту можно считать условие выполненным (или наоборот).

джава Stream.allMatch function comments

En
Stream.allMatch Returns whether all elements of the stream match the provided predicate