Stream.allMatch: примеры (JAVA)
Stream.allMatch(Predicate super T> 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) Валидация структуры объектов с комбинированными условиями
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) Применение с промежуточными операциями для ранней фильтрации
boolean res = users.stream()
.filter(u -> u.isActive())
.map(User::getScore)
.allMatch(score -> score >= 50);
System.out.println(res);
true или false в зависимости от данных
Пояснение: фильтрация уменьшает набор для проверки, что может улучшить производительность.
3) Использование с параллельным и неупорядоченным потоком для ускорения проверки
boolean res = bigCollection.parallelStream().unordered().allMatch(predicate);
System.out.println(res);
true или false
Пояснение: вызов unordered() позволяет внутреннему механизму лучше распараллеливать работу при отсутствии значимости порядка.
4) Комбинация с короткоживущим исключением и логированием
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 (без создания лишних объектов)
Pattern p = Pattern.compile("^[A-Z]{3}-\\d{4}$");
boolean ok = codes.stream().allMatch(p.asPredicate());
System.out.println(ok);
true или false
6) Пример с бесконечным потоком, где ожидается досрочная остановка
boolean res = Stream.iterate(0, n -> n + 1)
.allMatch(n -> n < 1000); // вернёт false при достижении 1000, но для этого требуется пройти все числа до 1000
System.out.println(res);
false
Пояснение: для бесконечных потоков нужно иметь условие, приводящее к false или использовать ограничение limit.
7) Оптимизация подсчёта с ранним выходом вместо коллекционирования
boolean allPositive = stream.peek(System.out::println)
.allMatch(x -> x > 0);
System.out.println(allPositive);
(печать элементов до первого не положительного)\nfalse/true
Пояснение: применение peek помогает отладить, сколько элементов проверено до срабатывания short-circuit.
8) Специальный случай: использование в сочетании с Optional
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
Пояснение: если коллекция отсутствует, по контексту можно считать условие выполненным (или наоборот).