← Назад к вопросам
С каким функциональным интерфейсом работает метод 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 выражения для читаемости