← Назад к вопросам

Что такое Predicate?

1.0 Junior🔥 151 комментариев
#Stream API и функциональное программирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Predicate в Java

Predicate — это функциональный интерфейс, который возвращает boolean значение. Используется для тестирования условий, фильтрации и проверки объектов. Введён в Java 8 как часть функционального программирования.

Определение Predicate

// Функциональный интерфейс с одним методом
@FunctionalInterface
public interface Predicate<T> {
    // Основной метод
    boolean test(T t);
    
    // Дополнительные методы для комбинирования
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
    
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }
    
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
}

Простые примеры

1. Базовое использование

// Predicate: проверить, является ли число чётным
Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(4));  // true
System.out.println(isEven.test(5));  // false

// Predicate: проверить длину строки
Predicate<String> hasLength = s -> s.length() > 3;
System.out.println(hasLength.test("Hello")); // true
System.out.println(hasLength.test("Hi"));    // false

2. Фильтрация в Stream API

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
Predicate<Integer> isEven = n -> n % 2 == 0;

// Фильтруем через Predicate
List<Integer> evenNumbers = numbers.stream()
    .filter(isEven)
    .collect(Collectors.toList());
// Результат: [2, 4, 6]

Комбинирование Predicates

1. Метод and()

Predicate<Integer> isEven = n -> n % 2 == 0;
Predicate<Integer> isGreaterThanFive = n -> n > 5;

// Комбинируем: чётное И больше 5
Predicate<Integer> combined = isEven.and(isGreaterThanFive);

List<Integer> numbers = Arrays.asList(1, 2, 4, 6, 8, 10);
List<Integer> result = numbers.stream()
    .filter(combined)
    .collect(Collectors.toList());
// Результат: [6, 8, 10]

2. Метод or()

Predicate<String> isShort = s -> s.length() < 3;
Predicate<String> startsWithA = s -> s.startsWith("A");

// ИЛИ коротко, ИЛИ начинается с A
Predicate<String> combined = isShort.or(startsWithA);

List<String> words = Arrays.asList("Hi", "Hello", "Apple", "Banana");
List<String> result = words.stream()
    .filter(combined)
    .collect(Collectors.toList());
// Результат: ["Hi", "Apple"]

3. Метод negate()

Predicate<Integer> isEven = n -> n % 2 == 0;

// Противоположное условие
Predicate<Integer> isOdd = isEven.negate();

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> oddNumbers = numbers.stream()
    .filter(isOdd)
    .collect(Collectors.toList());
// Результат: [1, 3, 5]

Практический пример: фильтрация объектов

class User {
    private String name;
    private int age;
    private String role;
    
    // конструктор, getters...
}

class UserFilter {
    public static void main(String[] args) {
        List<User> users = Arrays.asList(
            new User("Alice", 25, "ADMIN"),
            new User("Bob", 17, "USER"),
            new User("Charlie", 30, "ADMIN"),
            new User("David", 16, "USER")
        );
        
        // Predicates для разных условий
        Predicate<User> isAdult = user -> user.getAge() >= 18;
        Predicate<User> isAdmin = user -> "ADMIN".equals(user.getRole());
        Predicate<User> nameStartsWithA = user -> user.getName().startsWith("A");
        
        // Фильтруем: взрослые админы
        List<User> adminAdults = users.stream()
            .filter(isAdmin.and(isAdult))
            .collect(Collectors.toList());
        // Результат: Alice, Charlie
        
        // Фильтруем: админы ИЛИ имя начинается на A
        List<User> filtered = users.stream()
            .filter(isAdmin.or(nameStartsWithA))
            .collect(Collectors.toList());
        // Результат: Alice, Charlie
        
        // Фильтруем: НЕ взрослые
        List<User> minors = users.stream()
            .filter(isAdult.negate())
            .collect(Collectors.toList());
        // Результат: Bob, David
    }
}

Создание пользовательских методов с Predicate

class NumberUtils {
    // Метод, принимающий Predicate
    public static int countMatching(List<Integer> numbers, Predicate<Integer> predicate) {
        return (int) numbers.stream()
            .filter(predicate)
            .count();
    }
    
    // Использование
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        
        int evenCount = countMatching(numbers, n -> n % 2 == 0);
        int largeCount = countMatching(numbers, n -> n > 5);
        
        System.out.println("Even: " + evenCount); // 5
        System.out.println("Large: " + largeCount); // 5
    }
}

Predicate vs Function

// Function<T, R> — преобразует T в R
Function<String, Integer> stringToLength = s -> s.length();
Integer length = stringToLength.apply("Hello"); // 5

// Predicate<T> — тестирует T, возвращает boolean
Predicate<String> isLong = s -> s.length() > 3;
boolean result = isLong.test("Hello"); // true

Predicate в JPA/Hibernate

// Spring Data JPA с Predicate
public interface UserRepository extends 
    JpaRepository<User, Long>,
    QuerydslPredicateExecutor<User> { // Важно!
}

// Использование в сервисе
@Service
public class UserService {
    @Autowired
    private UserRepository repository;
    
    public List<User> findAdminUsers() {
        Predicate predicate = QUser.user
            .role.eq("ADMIN")
            .and(QUser.user.age.gt(18));
        
        return (List<User>) repository.findAll(predicate);
    }
}

Когда использовать Predicate

Используй Predicate:

  • Фильтрация коллекций (stream().filter())
  • Условные проверки (if, while)
  • Передача условий в методы
  • Создание переиспользуемых условий

Не используй, если:

  • Нужно преобразовать объект (используй Function)
  • Нужен результат другого типа (используй Function)

Заключение

Predicate — это мощный инструмент функционального программирования, который делает код:

  • Читаемым — ясно видны условия
  • Переиспользуемым — можно комбинировать predicates
  • Декларативным — что ты хочешь, а не как это сделать
  • Кратким — lambda выражения вместо анонимных классов