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

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

Описание Stream.noneMatch

Метод noneMatch из пакета java.util.stream служит для проверки, что ни один элемент стрима не удовлетворяет заданному предикату. Это терминальная операция, возвращающая логическое значение. Подходит для упрощённой валидации коллекций и потоков данных без явной итерации.

Сигнатуры основных версий:

  • boolean noneMatch(Predicate<? super T> predicate) - для общих объектов.
  • boolean noneMatch(IntPredicate predicate) - для IntStream.
  • boolean noneMatch(LongPredicate predicate) - для LongStream.
  • boolean noneMatch(DoublePredicate predicate) - для DoubleStream.

Поведение и особенности:

  • Возвращает true, если поток пустой или если ни один элемент не проходит предикат.
  • Короткое замыкание: при первом найденном элементе, для которого предикат возвращает true, метод завершает проверку и возвращает false.
  • Это терминальная операция: после вызова стрим считается использованным и дальнейшие операции над ним вызовут IllegalStateException.
  • Поддерживает параллельное выполнение. Для корректности предикат должен быть безопасен для многопоточного вызова при использовании параллельного стрима.
  • Если аргумент predicate равен null, будет брошено NullPointerException.

Возвращаемые значения:

  • true - ни один элемент не удовлетворяет предикату (включая случай пустого потока).
  • false - найден хотя бы один элемент, для которого предикат вернул true.

Типичные исключения и ситуации:

  • NullPointerException при null-предикате.
  • IllegalStateException при повторном использовании потока после терминальной операции.
  • Возможные побочные эффекты и некорректные результаты при небезопасных для параллелизма предикатах.

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

Ниже приведены компактные примеры разных случаев с кодом и результатом.

Пример 1. Базовая проверка в списке

import java.util.*;
import java.util.stream.*;

List<String> names = Arrays.asList("Anna", "Bob", "Carl");
boolean noneStartsWithD = names.stream().noneMatch(s -> s.startsWith("D"));
System.out.println(noneStartsWithD);
true

Пример 2. Найдено совпадение

List<Integer> nums = Arrays.asList(1, 2, 3, 4);
boolean noneEven = nums.stream().noneMatch(n -> n % 2 == 0);
System.out.println(noneEven);
false

Пример 3. Пустой поток

boolean noneMatchEmpty = Stream.empty().noneMatch(x -> true);
System.out.println(noneMatchEmpty);
true

Пример 4. Примитивный стрим (IntStream)

import java.util.stream.*;

boolean noneNegative = IntStream.of(1, 2, 3).noneMatch(i -> i < 0);
System.out.println(noneNegative);
true

Пример 5. Параллельный стрим

List<String> words = Arrays.asList("alpha", "beta", "gamma", "delta");
boolean noneLong = words.parallelStream().noneMatch(w -> w.length() > 10);
System.out.println(noneLong);
true

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

В экосистеме потоков есть несколько методов с близким смыслом. Краткое сравнение:

  • anyMatch - возвращает true, если найден хотя бы один элемент, удовлетворяющий предикату. Противоположен noneMatch по логике при простом отрицании.
  • allMatch - возвращает true, если все элементы удовлетворяют предикату. Зависимость: allMatch(p) эквивалентен !anyMatch(x -> !p.test(x)).
  • filter + findAny/isPresent - альтернативный способ проверки отсутствия элементов: stream.filter(p).findAny().isPresent() эквивалентен !noneMatch(p), но менее лаконичен.
  • count() - иногда используется как stream.filter(p).count() == 0, но это менее эффективно, так как не коротко замыкается и может посчитать все элементы.

Выбор между ними зависит от читаемости и требований к производительности. Для наиболее простого и эффективного выражения «ни один элемент не подходит» предпочтительнее noneMatch. Для проверки «есть ли хотя бы один» лучше использовать anyMatch. При необходимости считать количество совпадений используется count, но он обходится дороже из-за отсутствия короткого замыкания.

Аналоги в других языках

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

JavaScript

const arr = [1, 2, 3];
const noneEven = !arr.some(x => x % 2 === 0);
console.log(noneEven);
false

В JS нет встроенного noneMatch, вместо этого используется отрицание some или проверка every с инвертированным предикатом.

Python

nums = [1, 2, 3]
none_even = not any(n % 2 == 0 for n in nums)
print(none_even)
False

Используются генераторы, short-circuit работает для any/all.

PHP

$arr = [1,2,3];
$none = count(array_filter($arr, function($x){ return $x % 2 === 0; })) === 0;
var_dump($none);
bool(false)

В PHP нет прямого noneMatch; применяются array_filter или цикл.

SQL

-- Проверка, что нет строк с age < 0
SELECT NOT EXISTS (SELECT 1 FROM users WHERE age < 0) AS none_negative;
none_negative
-------------
true

В SQL структура запросов и оптимизации отличаются; используется NOT EXISTS или COUNT = 0.

C# (LINQ)

using System.Linq;
var nums = new[]{1,2,3};
var noneEven = !nums.Any(n => n % 2 == 0);
Console.WriteLine(noneEven);
False

LINQ имеет Any и All; прямого NoneMatch нет, но эквивалент через отрицание Any применим.

Kotlin

val nums = listOf(1,2,3)
val noneEven = nums.none { it % 2 == 0 }
println(noneEven)
false

Kotlin предоставляет удобный none как стандартную коллекционную функцию; семантика аналогична Java noneMatch.

Go

package main
import "fmt"
func main(){
    nums := []int{1,2,3}
    noneEven := true
    for _, v := range nums {
        if v%2 == 0 { noneEven = false; break }
    }
    fmt.Println(noneEven)
}
false

В Go нет встроенного функционального none; используется явная итерация.

Lua

local nums = {1,2,3}
local none = true
for _,v in ipairs(nums) do
  if v % 2 == 0 then none = false; break end
end
print(none)
false

Во многих языках отсутствует единый метод noneMatch, но поведение воспроизводится через отрицание наличия совпадений или явную проверку.

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

  • Передача null-предиката. Приводит к NullPointerException.
  • Повторное использование стрима. После терминальной операции последующие обращения к тому же стриму дают IllegalStateException.
  • Ожидание полного перебора при параллельном запуске. noneMatch коротко замыкается, но при параллельном выполнении может быть проверено больше элементов, чем минимально необходимо, из-за распараллеливания. Предикат должен быть потокобезопасным.
  • Побочные эффекты в предикате. Изменение внешнего состояния внутри предиката может привести к непредсказуемому поведению, особенно в параллельном режиме.

Пример 1. NullPredicate

Stream.of(1,2,3).noneMatch(null);
Exception in thread "main" java.lang.NullPointerException
    at java.util.Objects.requireNonNull(Objects.java:...) 
    at java.util.stream.ReferencePipeline.noneMatch(ReferencePipeline.java:...)

Пример 2. Повторное использование стрима

Stream<Integer> s = Stream.of(1,2,3);
s.noneMatch(i -> i < 0);
s.noneMatch(i -> i < 10);
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
    at java.util.stream.ReferencePipeline.evaluate(...)

Пример 3. Побочные эффекты и параллельность

import java.util.concurrent.atomic.AtomicInteger;

AtomicInteger counter = new AtomicInteger();
boolean none = IntStream.range(0, 1000).parallel().noneMatch(i -> {
    counter.incrementAndGet();
    return i == 9999; // никогда не сработает
});
System.out.println(counter.get());
System.out.println(none);
(значение может превышать минимально необходимое из-за параллельной обработки)
true

В примере подсчёт демонстрирует, что параллельный режим может вызвать больше проверок, поэтому ненадёжно полагаться на точное число выполнений предиката.

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

Метод noneMatch введён в Java 8 вместе с общей Streams API. С момента введения сигнатура и поведение не претерпели значительных изменений. Поддержка примитивных стримов (IntStream, LongStream, DoubleStream) также появилась в Java 8 и имеет свои специализированные предикаты.

В последующих версиях JDK были улучшены внутренние оптимизации и производительность стримов, а также исправлены баги, но сама контрактная семантика noneMatch осталась прежней.

Расширенные примеры и нетривиальные сценарии

Несколько более сложных случаев применения noneMatch с пояснениями.

Пример 1. Проверка файла на отсутствие строки с ключевым словом

Пример java
import java.nio.file.*;
import java.io.IOException;

try {
    boolean none = Files.lines(Paths.get("log.txt"))
        .noneMatch(line -> line.contains("ERROR"));
    System.out.println(none);
} catch (IOException e) {
    e.printStackTrace();
}
true  // если в файле нет строк с ERROR

Использование noneMatch с Files.lines полезно для ленивой проверки больших файлов; поток закроется корректно при завершении.

Пример 2. Бесконечный стрим и осторожность

Пример java
import java.util.stream.Stream;

boolean none = Stream.iterate(1, n -> n + 1)
    .noneMatch(n -> n > 0 && n > 1000000); // условие всегда ложно для начального фрагмента
System.out.println(none);
(программа может не завершиться или выполниться долго)

С бесконечными стримами применение noneMatch требует гарантий достижения удовлетворяющего элемента или внешнего предела; лучше сочетать с limit или использовать findFirst/anyMatch на ограниченном диапазоне.

Пример 3. Комбинация map и noneMatch

Пример java
record User(String name, String email) {}

List<User> users = List.of(new User("A","a@x"), new User("B","b@x"));
boolean noneInvalidEmail = users.stream()
    .map(User::email)
    .noneMatch(e -> !e.contains("@"));
System.out.println(noneInvalidEmail);
true

Сначала применяется преобразование, затем проверка: удобно для проверки свойств конкретного поля.

Пример 4. Использование со сложными состояниями и потокобезопасность

Пример java
import java.util.concurrent.atomic.AtomicBoolean;

List<Integer> data = IntStream.range(0,1000).boxed().toList();
AtomicBoolean seen = new AtomicBoolean(false);
boolean none = data.parallelStream().noneMatch(i -> {
    if (i == 500) seen.set(true);
    return i > 100000; // всегда false
});
System.out.println(none + ", seen=" + seen.get());
true, seen=true

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

Пример 5. Сравнение с filter + findAny по производительности

Пример java
// оба варианта эквивалентны по логике, но noneMatch короче и обычно эффективнее
boolean v1 = list.stream().noneMatch(p);
boolean v2 = !list.stream().filter(p).findAny().isPresent();
System.out.println(v1 + ", " + v2);
true, true

noneMatch обеспечивает более прямую проверку и читабельность. В некоторых реализациях filter+findAny может создавать дополнительные промежуточные этапы, но семантически оба варианта дают схожий результат.

джава Stream.noneMatch function comments

En
Stream.noneMatch Returns whether no elements of the stream match the provided predicate