Как отфильтровать коллекцию в Java по условию (предикату)?
Использование Stream API и Predicate для фильтрации коллекций
Ваш подход с циклом for абсолютно рабочий, но с Java 8 появился более лаконичный и функциональный способ — Stream API. Он позволяет обрабатывать коллекции в стиле "цепочки вызовов" (pipeline). Для фильтрации используется метод filter(), который принимает объект Predicate — функциональный интерфейс с методом test(T t), возвращающим boolean.
Пример 1: Фильтрация через лямбда-выражение
Самый простой способ — передать лямбду прямо в filter():
List<Person> adults = people.stream()
.filter(p -> p.getAge() >= 18)
.collect(Collectors.toList());
Здесь .stream() создаёт поток из списка, filter оставляет только элементы, удовлетворяющие условию, а collect(Collectors.toList()) собирает результат обратно в список.
Пример 2: Вынос условия в отдельный предикат
Если условие сложное или используется многократно, его можно вынести в переменную типа Predicate:
Predicate<Person> isAdult = person -> person.getAge() >= 18;
List<Person> adults = people.stream()
.filter(isAdult)
.collect(Collectors.toList());
Пример 3: Комбинирование нескольких предикатов
Предикаты можно объединять через методы and(), or(), negate():
Predicate<Person> isAdult = p -> p.getAge() >= 18;
Predicate<Person> nameStartsWithA = p -> p.getName().startsWith("A");
List<Person> result = people.stream()
.filter(isAdult.and(nameStartsWithA)) // взрослые И с именем на A
.collect(Collectors.toList());
Пример 4: Фильтрация с помощью метода ссылки
Если у вас уже есть метод, проверяющий условие, можно использовать ссылку на метод:
public static boolean isAdult(Person p) {
return p.getAge() >= 18;
}
// Использование:
List<Person> adults = people.stream()
.filter(MyClass::isAdult)
.collect(Collectors.toList());
Альтернативы без Stream API
- Java 8+ с методом
removeIf()— изменяет исходную коллекцию, удаляя элементы, не прошедшие условие (обратная логика):
people.removeIf(p -> p.getAge() < 18); - Apache Commons Collections — утилита
CollectionUtils.filter(), но она тоже мутирует коллекцию и требует зависимость. - Google Guava — класс
FluentIterableс методомfilter(), похож на Stream API.
Рекомендация
Для современных проектов на Java 8+ используйте Stream API — это стандартный, читаемый и гибкий инструмент. Он не меняет исходную коллекцию (если не использовать removeIf), что безопаснее. Лямбды и ссылки на методы делают код компактным, а комбинирование предикатов позволяет строить сложные условия без вложенных циклов.
Ваш пример с циклом можно переписать в одну строку — и это будет понятно любому Java-разработчику, знакомому с функциональным стилем.
<<Использование метода removeIf() для фильтрации с изменением исходной коллекции
Если вам не нужно сохранять исходный список, а требуется отфильтровать его "на месте", можно воспользоваться методом removeIf(), который появился в Java 8 в интерфейсе Collection. Он принимает Predicate и удаляет все элементы, удовлетворяющие условию.
Важно: логика обратная — вы передаёте предикат для удаления, а не для сохранения. Чтобы оставить только взрослых, нужно удалить тех, кто младше 18:
people.removeIf(p -> p.getAge() < 18);
// Теперь people содержит только совершеннолетних
Когда это удобно?
- Когда исходная коллекция больше не нужна в неизменном виде.
- Когда вы работаете с большими данными и не хотите создавать новый список (экономия памяти).
- В случаях, когда нужно модифицировать коллекцию, переданную в метод, и вернуть её же (например, в builder-паттернах).
Недостатки
- Метод изменяет исходный объект, что может привести к побочным эффектам.
- Нельзя использовать с неизменяемыми коллекциями (например,
List.of()выбросит исключение). - Не подходит, если нужно сохранить обе версии (исходную и отфильтрованную).
В остальном это простой и эффективный способ, особенно когда логика фильтрации тривиальна и вы уверены, что исходный список не понадобится.
Ответов пока нет.
Войдите чтобы оставить ответ