DistinctBy в API Java Stream

DistinctBy в API Java Stream

1. обзор

Поиск различных элементов в списке является одной из общих задач, с которыми мы, программисты, обычно сталкиваемся. Начиная с Java 8 с добавлениемStreams, у нас появился новый API для обработки данных с использованием функционального подхода.

В этой статье мы покажем различные альтернативы фильтрации коллекции с использованием определенного атрибута объектов в списке.

2. Использование Stream API

Stream API предоставляет методdistinct(), который возвращает различные элементы списка на основе методаequals() классаObject.

Однако он становится менее гибким, если мы хотим фильтровать по определенному атрибуту. Одна из альтернатив, которую мы имеем, - написать фильтр, который поддерживает состояние.

2.1. Использование фильтра с отслеживанием состояния

Одним из возможных решений было бы реализоватьPredicate: с отслеживанием состояния.

public static  Predicate distinctByKey(
    Function keyExtractor) {

    Map 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
}

А чтобы получить новую отфильтрованную коллекцию поname, мы можем использовать:

List personListFiltered = personList.stream()
  .filter(distinctByKey(p -> p.getName()))
  .collect(Collectors.toList());

3. Использование коллекций Eclipse

Eclipse Collections - это библиотека, которая предоставляет дополнительные методы для обработкиStreams и коллекций в Java.

3.1. ИспользуяListIterate.distinct()

МетодListIterate.distinct() позволяет нам фильтроватьStream, используя различныеHashingStrategies.. Эти стратегии могут быть определены с использованием лямбда-выражений или ссылок на методы.

Если мы хотим выполнить фильтрацию по имениPerson’s:

List personListFiltered = ListIterate
  .distinct(personList, HashingStrategies.fromFunction(Person::getName));

Или, если атрибут, который мы собираемся использовать, является примитивным (int, long, double), мы можем использовать специализированную функцию, подобную этой:

List personListFiltered = ListIterate.distinct(
  personList, HashingStrategies.fromIntFunction(Person::getAge));

3.2. Maven Dependency

Чтобы использовать Коллекции Eclipse в нашем проекте, нам нужно добавить следующие зависимости к нашемуpom.xml:


    org.eclipse.collections
    eclipse-collections
    8.2.0

Вы можете найти последнюю версию библиотеки Eclipse Collections в репозиторииMaven Central.

Чтобы узнать больше об этой библиотеке, мы можем перейти кthis article.

4. Using Vavr (Javaslang *) *

Это функциональная библиотека для Java 8, которая предоставляет неизменяемые данные и функциональные структуры управления.

4.1. ИспользуяList.distinctBy

Для фильтрации списков этот класс предоставляет свой собственный класс List, в котором есть методdistinctBy(), который позволяет нам фильтровать по атрибутам объектов, которые он содержит:

List personListFiltered = List.ofAll(personList)
  .distinctBy(Person::getName)
  .toJavaList();

4.2. Maven Dependency

Мы добавим следующие зависимости к нашемуpom.xml, чтобы использовать Vavr в нашем проекте.


    io.vavr
    vavr
    0.9.0

Вы можете найти последнюю версию библиотеки Vavr в репозиторииMaven Central.

Чтобы узнать больше об этой библиотеке, мы можем перейти кthis article.

5. Использование StreamEx

Эта библиотека предоставляет полезные классы и методы для обработки потоков Java 8.

5.1. ИспользуяStreamEx.distinct

В предоставленных классах естьStreamEx, у которого есть методdistinct, которому мы можем отправить ссылку на атрибут, который мы хотим отличить:

List personListFiltered = StreamEx.of(personList)
  .distinct(Person::getName)
  .toList();

5.2. Maven Dependency

Мы добавим следующие зависимости к нашемуpom.xml, чтобы использовать StreamEx в нашем проекте.


    one.util
    streamex
    0.6.5

Вы можете найти последнюю версию библиотеки StreamEx в репозиторииMaven Central.

6. Заключение

В этом кратком руководстве мы рассмотрели примеры получения различных элементов потока на основе атрибута с использованием стандартного API Java 8 и дополнительных альтернатив другим библиотекам.

Как всегда доступен полный кодover on GitHub.

Related