1. Обзор
Поиск различных элементов в списке — одна из распространенных задач, с которыми мы, программисты, обычно сталкиваемся. Начиная с Java 8, с включением потоков
, у нас есть новый API для обработки данных с использованием функционального подхода.
В этой статье мы покажем различные альтернативы фильтрации коллекции с использованием определенного атрибута объектов в списке.
2. Использование потокового API
Stream API предоставляет метод different ()
, возвращающий различные элементы списка на основе метода equals() класса
Object
.
Однако он становится менее гибким, если мы хотим фильтровать по определенному атрибуту. Одна из имеющихся у нас альтернатив — написать фильтр, сохраняющий состояние.
2.1. Использование фильтра с отслеживанием состояния
Одним из возможных решений может быть реализация предиката с отслеживанием состояния:
public static <T> Predicate<T> distinctByKey(
Function<? super T, ?> keyExtractor) {
Map<Object, Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
Чтобы проверить это, мы будем использовать следующий класс Person
с атрибутами age
, email
и name:
public class Person {
private int age;
private String name;
private String email;
// standard getters and setters
}
И чтобы получить новую отфильтрованную коллекцию по имени
, мы можем использовать:
List<Person> personListFiltered = personList.stream()
.filter(distinctByKey(p -> p.getName()))
.collect(Collectors.toList());
3. Использование коллекций Eclipse
Eclipse Collections — это библиотека, предоставляющая дополнительные методы для обработки потоков
и коллекций в Java.
3.1. Использование ListIterate.distinct()
Метод ListIterate.distinct()
позволяет нам фильтровать поток
, используя различные стратегии хеширования.
Эти стратегии можно определить с помощью лямбда-выражений или ссылок на методы.
Если мы хотим отфильтровать по имени человека
:
List<Person> personListFiltered = ListIterate
.distinct(personList, HashingStrategies.fromFunction(Person::getName));
Или, если атрибут, который мы собираемся использовать, является примитивным (int, long, double), мы можем использовать специализированную функцию, подобную этой:
List<Person> personListFiltered = ListIterate.distinct(
personList, HashingStrategies.fromIntFunction(Person::getAge));
3.2. Зависимость от Maven
Нам нужно добавить следующие зависимости в наш pom.xml
, чтобы использовать Eclipse Collections в нашем проекте:
<dependency>
<groupId>org.eclipse.collections</groupId>
<artifactId>eclipse-collections</artifactId>
<version>8.2.0</version>
</dependency>
Вы можете найти последнюю версию библиотеки коллекций Eclipse в репозитории Maven Central .
Чтобы узнать больше об этой библиотеке, мы можем перейти к этой статье .
4. Использование Vavr ( Javaslang )
Это функциональная библиотека для Java 8, предоставляющая неизменяемые данные и структуры функционального управления.
4.1. Использование List.distinctBy
Для фильтрации списков этот класс предоставляет свой собственный класс List, который имеет метод DifferentBy()
, который позволяет нам фильтровать по атрибутам содержащихся в нем объектов:
List<Person> personListFiltered = List.ofAll(personList)
.distinctBy(Person::getName)
.toJavaList();
4.2. Зависимость от Maven
Мы добавим следующие зависимости в наш pom.xml
, чтобы использовать Vavr в нашем проекте.
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
<version>0.9.0</version>
</dependency>
Вы можете найти последнюю версию библиотеки Vavr в репозитории Maven Central .
Чтобы узнать больше об этой библиотеке, мы можем перейти к этой статье .
5. Использование StreamEx
Эта библиотека предоставляет полезные классы и методы для обработки потоков Java 8.
5.1. Использование StreamEx.distinct
В предоставленных классах есть StreamEx
, у которого есть отдельный
метод, которому мы можем отправить ссылку на атрибут, который мы хотим выделить:
List<Person> personListFiltered = StreamEx.of(personList)
.distinct(Person::getName)
.toList();
5.2. Зависимость от Maven
Мы добавим следующие зависимости в наш pom.xml
, чтобы использовать StreamEx в нашем проекте.
<dependency>
<groupId>one.util</groupId>
<artifactId>streamex</artifactId>
<version>0.6.5</version>
</dependency>
Вы можете найти последнюю версию библиотеки StreamEx в репозитории Maven Central .
6. Заключение
В этом кратком руководстве мы рассмотрели примеры того, как получить различные элементы потока на основе атрибута с использованием стандартного API Java 8 и дополнительных альтернатив с другими библиотеками.
Как всегда, полный код доступен на GitHub .