Статьи

Разработка API коллекций Eclipse

Eclipse Collections — это платформа Java Collections с открытым исходным кодом, которая позволяет писать функциональный, свободный код на Java.

история
Eclipse Collections начиналась как фреймворк коллекций под названием Caramel в Goldman Sachs в 2004 году. С тех пор фреймворк развивался, и в 2012 году он был открыт для GitHub в качестве проекта GS Collections. За эти годы около 40 или около того разработчиков из одной компании внесли свой вклад в структуру коллекций. Чтобы максимально использовать возможности проекта с открытым исходным кодом, GS Collections был перенесен в Eclipse Foundation, который в 2015 году был переименован в Eclipse Collections. Теперь эта структура полностью открыта для сообщества и принимает взносы!

Цели дизайна
Eclipse Collections была разработана для предоставления многофункционального, функционального, свободного и интересного API, а также структур данных с эффективным использованием памяти, обеспечивая при этом совместимость с коллекциями Java. Он предоставляет отсутствующие типы, такие как Bag , Multimap , Stack , BiMap , Interval .

Эволюция рамок
За последние 14 с лишним лет фреймворк стал более RichIterable обладает наивысшим интерфейсом: теперь в RichIterable содержится более 100 методов. Эти методы были включены в интерфейс после тщательного обсуждения. Ниже приведены шаги, которые мы предпринимаем при добавлении API:

1. Вариант использования: большинство методов, добавленных в платформу, мотивируются требованиями пользователя. Пользователи будут поднимать либо проблему, либо напрямую запрос на извлечение проекта, а затем мы начинаем обсуждение.

2. Static Utility vs API: Eclipse Collections имеет статические служебные классы, такие как ListIterate , ListIterate и т. Д. Эти статические служебные классы позволяют нам ListIterate прототипы наших функций перед добавлением их в качестве API. Если методы статической утилиты интенсивно используются, то в следующем выпуске мы попытаемся реализовать этот метод в виде API на интерфейсе коллекции, чтобы обеспечить богатый и свободный опыт кодирования.

Например: Iterate#groupByAndCollect() в настоящее время реализован в статической утилите. Поскольку этот метод часто используется, он оправдывает добавление его в качестве API в RichIterable чтобы обеспечить богатый, функциональный и свободный опыт кодирования. Существует открытая проблема, если вы хотите помочь нам.

3. Переопределения ковариантов. Мы логически переопределяем методы API, так что API возвращает тип, соответствующий его поведению.

Например: RichIterable имеет API-интерфейс select() который похож на filter() который возвращает все элементы коллекций, которые оценивают значение true для Predicate . Ниже описано, как API определяется на каждом интерфейсе:

1
2
3
4
5
6
7
8
// RichIterable
RichIterable<T> select(Predicate<? super T> predicate);
 
// ListIterable
ListIterable<T> select(Predicate<? super T> predicate);
 
// MutableList
MutableList<T> select(Predicate<? super T> predicate)

Как вы можете видеть, select() на
RichIterable возвращает RichIterable
ListIterable возвращает ListIterable
MutableList возвращает MutableList

4. Перегрузка с помощью Target. Иногда возможно, что нам нужна коллекция, отличная от возвращенной. Чтобы сделать его эффективным и быстрым, мы создаем перегруженный метод, который принимает целевую коллекцию. Целевые коллекции используются для накопления результатов и возврата целевой коллекции.

Например: как описано выше, метод select() в MutableList возвращает MutableList . Тем не менее, что если вы хотите MutableSet ? Доступен перегруженный метод select() который принимает целевую коллекцию, которая может быть набором.

1
2
3
4
5
6
7
8
9
MutableList<Integer> integers = Lists.mutable.with(
        1, 2, 2, 3, 3, 3, 4, 4, 4, 4);
MutableList<Integer> evens = integers.select(each -> each % 2 == 0);
Assert.assertEquals(Lists.mutable.with(2, 2, 4, 4, 4, 4), evens);
 
MutableSet<Integer> uniqueEvens = integers.select(
        each -> each % 2 == 0,
        Sets.mutable.empty());
Assert.assertEquals(Sets.mutable.with(2, 4), uniqueEvens);

5. Симметрия: Eclipse Collections предлагает примитивные коллекции. Мы стараемся поддерживать симметрию между коллекциями объектов и примитивными коллекциями, чтобы обеспечить полное взаимодействие с пользователем.

Реализация API на практике

Давайте реализуем простой API RichIterable#countBy() который был добавлен в выпуске Eclipse Collections 9.0.0: Мотивация для этого API была пользователями, которые упоминали о необходимости collect() коллекцию в Bag . В Eclipse Collections collect() похож на map() а Bag — это структура данных, которая поддерживает отображение объекта на счетчик.

1
2
3
4
5
6
7
8
9
MutableList<String> strings = Lists.mutable.with(
        "1", "2", "2", "3", "3", "3", "4", "4", "4", "4");
Bag<Integer> integers = strings.collect(
        Integer::valueOf,
        Bags.mutable.empty());
Assert.assertEquals(1, integers.occurrencesOf(1));
Assert.assertEquals(2, integers.occurrencesOf(2));
Assert.assertEquals(3, integers.occurrencesOf(3));
Assert.assertEquals(4, integers.occurrencesOf(4));

Приведенное выше решение для подсчета целых чисел сработало, однако оно не было интуитивно понятным. Неопытному разработчику может быть трудно реализовать это решение. Итак, мы решили добавить countBy() и теперь код выглядит более функциональным, плавным и, более того, интуитивно понятным.

1
2
3
4
5
6
7
MutableList<String> strings = Lists.mutable.with(
        "1", "2", "2", "3", "3", "3", "4", "4", "4", "4");
Bag<Integer> integers = strings.countBy(Integer::valueOf);
Assert.assertEquals(1, integers.occurrencesOf(1));
Assert.assertEquals(2, integers.occurrencesOf(2));
Assert.assertEquals(3, integers.occurrencesOf(3));
Assert.assertEquals(4, integers.occurrencesOf(4));

Резюме

В этом блоге я объяснил стратегию развития зрелой библиотеки коллекций Java. Мы рассматриваем следующие аспекты: сценарий использования, утилита и API, ковариантные переопределения, необходимые перегрузки и, наконец, симметрия.

сноска
Это личная цель — получить 1000 звезд в нашем проекте GitHub , поэтому, если вам нравится среда, продемонстрируйте свою поддержку и поставьте звезду в хранилище.

Опубликовано на Java Code Geeks с разрешения Nikhil Navidadekar
, партнер нашей программы JCG . Смотрите оригинальную статью здесь: API дизайн коллекций Eclipse

Мнения, высказанные участниками Java Code Geeks, являются их собственными.