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

С каким функциональным интерфейсом работает метод filter

2.2 Middle🔥 241 комментариев
#Stream API и функциональное программирование#Основы Java

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

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

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

С каким функциональным интерфейсом работает метод filter

Метод filter() в Stream API работает с функциональным интерфейсом Predicate<T>.

Что такое Predicate

Predicate<T> — это функциональный интерфейс из пакета java.util.function, который:

  • Принимает один аргумент типа T
  • Возвращает boolean (true или false)
  • Имеет один абстрактный метод: boolean test(T t)
@FunctionalInterface
public interface Predicate<T> {
    /**
     * Evaluates this predicate on the given argument.
     * @param t the input argument
     * @return true if the input argument matches the predicate,
     * otherwise false
     */
    boolean test(T t);
    
    // Дополнительные методы (default)
    default Predicate<T> and(Predicate<? super T> other) { ... }
    default Predicate<T> or(Predicate<? super T> other) { ... }
    default Predicate<T> negate() { ... }
}

Сигнатура метода filter

Stream<T> filter(Predicate<? super T> predicate)

Метод filter() принимает объект типа Predicate<T> и возвращает новый Stream с элементами, для которых predicate вернул true.

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

1. Используя lambda выражение:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

// Lambda выражение - реализация Predicate
numbers.stream()
    .filter(n -> n > 3)  // Predicate<Integer>: (Integer) -> boolean
    .forEach(System.out::println);

// Вывод:
// 4
// 5
// 6

2. Используя ссылку на метод:

class NumberValidator {
    public static boolean isEven(Integer n) {
        return n % 2 == 0;
    }
}

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

numbers.stream()
    .filter(NumberValidator::isEven)  // Ссылка на метод - реализация Predicate
    .forEach(System.out::println);

// Вывод:
// 2
// 4
// 6

3. Используя анонимный класс:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

names.stream()
    .filter(new Predicate<String>() {
        @Override
        public boolean test(String name) {
            return name.length() > 3;
        }
    })
    .forEach(System.out::println);

// Вывод:
// Alice
// Charlie

4. Используя переменную типа Predicate:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Объявляем Predicate
Predicate<Integer> isPositive = n -> n > 0;

// Используем её в filter
numbers.stream()
    .filter(isPositive)
    .forEach(System.out::println);

// Вывод: 1, 2, 3, 4, 5 (все положительные)

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

Predicate имеет методы для комбинирования условий:

1. and() — логическое И

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

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

numbers.stream()
    .filter(isEven.and(isGreaterThanThree))  // n % 2 == 0 AND n > 3
    .forEach(System.out::println);

// Вывод:
// 4
// 6

2. or() — логическое ИЛИ

Predicate<String> startsWithA = s -> s.startsWith("A");
Predicate<String> startsWithB = s -> s.startsWith("B");

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Diana");

names.stream()
    .filter(startsWithA.or(startsWithB))  // Starts with A OR B
    .forEach(System.out::println);

// Вывод:
// Alice
// Bob

3. negate() — логическое НЕ

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

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

numbers.stream()
    .filter(isEven.negate())  // NOT even = odd
    .forEach(System.out::println);

// Вывод:
// 1
// 3
// 5

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

public class User {
    private String name;
    private int age;
    private boolean isActive;
    
    public User(String name, int age, boolean isActive) {
        this.name = name;
        this.age = age;
        this.isActive = isActive;
    }
    
    public String getName() { return name; }
    public int getAge() { return age; }
    public boolean isActive() { return isActive; }
}

List<User> users = Arrays.asList(
    new User("Alice", 25, true),
    new User("Bob", 17, true),
    new User("Charlie", 30, false),
    new User("Diana", 22, true)
);

// Фильтруем активных пользователей старше 20
List<User> filtered = users.stream()
    .filter(User::isActive)                    // Predicate 1
    .filter(user -> user.getAge() > 20)        // Predicate 2
    .collect(Collectors.toList());

System.out.println(filtered.size());  // 2 (Alice, Diana)

// Или используя комбинирование
Predicate<User> isAdult = u -> u.getAge() >= 18;
Predicate<User> isActive = User::isActive;

List<User> filtered2 = users.stream()
    .filter(isAdult.and(isActive))
    .collect(Collectors.toList());

System.out.println(filtered2.size());  // 2

Другие функциональные интерфейсы в java.util.function

// Function<T, R> - преобразование (T -> R)
Stream<String> fruits = Stream.of("apple", "banana");
fruits.map(String::toUpperCase);  // Function<String, String>

// Consumer<T> - выполнить действие над T (T -> void)
fruits.forEach(System.out::println);  // Consumer<String>

// Supplier<T> - создать T (void -> T)
Stream.generate(() -> "hello");  // Supplier<String>

// BiFunction<T, U, R> - (T, U) -> R
IntStream.range(1, 5)
    .reduce(1, (a, b) -> a * b);  // BiFunction<Integer, Integer, Integer>

Сравнение способов использования filter

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Способ 1: Lambda (самый читаемый)
numbers.stream()
    .filter(n -> n > 2)
    .collect(Collectors.toList());

// Способ 2: Ссылка на метод
numbers.stream()
    .filter(NumberValidator::isGreaterThanTwo)
    .collect(Collectors.toList());

// Способ 3: Переиспользуемый Predicate
Predicate<Integer> greaterThanTwo = n -> n > 2;
numbers.stream()
    .filter(greaterThanTwo)
    .collect(Collectors.toList());

// Способ 4: Комплексный Predicate
Predicate<Integer> even = n -> n % 2 == 0;
Predicate<Integer> greaterThanTwo = n -> n > 2;
numbers.stream()
    .filter(even.and(greaterThanTwo))
    .collect(Collectors.toList());

Итоги

Метод filter() работает с Predicate<T>:

  • Predicate<T> — функциональный интерфейс, возвращающий boolean
  • Основной метод: boolean test(T t)
  • Используется для: выделения элементов, удовлетворяющих условию
  • Способы реализации: lambda, ссылка на метод, анонимный класс
  • Комбинирование: and(), or(), negate()
  • Рекомендация: используй lambda выражения для читаемости
С каким функциональным интерфейсом работает метод filter | PrepBro