Введение в коллекции Eclipse

Введение в коллекции Eclipse

1. обзор

Eclipse Collections - еще одна улучшенная среда сбора данных для Java.

Проще говоря, он предоставляет оптимизированные реализации, а также некоторые дополнительные структуры данных и функции, которых нет в ядре Java.

Библиотека предоставляет как изменчивые, так и неизменные реализации всех структур данных.

2. Maven Dependency

Начнем с добавления следующей зависимости Maven к нашемуpom.xml:

org.eclipse.collections
    eclipse-collections
    8.2.0

Последнюю версию библиотеки можно найти в папкеMaven Central Repository.

3. Большая картина

3.1. Основные типы коллекций

Основные типы коллекций в коллекциях Eclipse:

  • ListIterable - упорядоченная коллекция, которая поддерживает порядок вставки и допускает дублирование элементов. Подинтерфейсы включают:MutableList,FixedSizeList иImmutableList. Самый распространенныйListIterable implementation is FastList, which is a subclass of MutableList

  • SetIterable - коллекция, не допускающая повторяющихся элементов. Это может быть отсортировано или не отсортировано. Подинтерфейсы включают:SortedSetIterable иUnsortedSetIterable.. Самая распространенная несортированная реализацияSetIterable -UnifiedSet

  • MapIterable - набор пар ключ / значение. Подинтерфейсы включаютMutableMap,FixedSizeMap иImmutableMap. Двумя распространенными реализациями являютсяUnifiedMap иMutableSortedMap. В то время какUnifiedMap не поддерживает какой-либо порядок,MutableSortedMap поддерживает естественный порядок элементов

  • BiMap - набор пар ключ / значение, которые можно повторять в любом направлении. BiMap расширяет интерфейсMapIterable

  • Bag - неупорядоченная коллекция, допускающая дубликаты. Подинтерфейсы включаютMutableBag andFixedSizeBag. Наиболее распространенная реализация -HashBag

  • StackIterable - коллекция, которая поддерживает порядок «последний вошел, первый ушел», перебирая элементы в обратном порядке вставки. Подинтерфейсы включаютMutableStack иImmutableStack

  • MultiMap - набор пар ключ / значение, допускающий несколько значений для каждого ключа

3.2. Примитивные коллекции

The framework also provides a huge set of primitive collections; их реализации названы в соответствии с их типом. Существуют изменяемые, неизменяемые, синхронизированные и неизменяемые формы для каждого их типа:

  • ПримитивLists

  • ПримитивSets

  • ПримитивStacks

  • ПримитивBags

  • ПримитивMaps

  • IntInterval

Существует огромное количество примитивных форм карт, охватывающих все возможные комбинации примитивных или объектных ключей и примитивных или объектных значений.

Небольшое примечание -IntInterval - это диапазон целых чисел, который можно повторять, используя значение шага.

4. Создание коллекции

Чтобы добавить элементы вArrayList илиHashSet, мы создаем экземпляр коллекции, вызывая конструктор no-arg, а затем добавляя каждый элемент один за другим.

Хотя мы все еще можем сделать это в коллекциях Eclipse,we can also instantiate a collection and provide all initial elements at the same time in a single line.

Давайте посмотрим, как мы можем создать экземплярFastList:

MutableList list = FastList.newListWith(
  "Porsche", "Volkswagen", "Toyota", "Mercedes", "Toyota");

Точно так же мы можем создать экземплярUnifiedSet и добавить к нему элементы, передав элементы статическому методуnewSetWith():

Set comparison = UnifiedSet.newSetWith(
  "Porsche", "Volkswagen", "Toyota", "Mercedes");

Вот как мы можем создатьHashBag:

MutableBag bag = HashBag.newBagWith(
  "Porsche", "Volkswagen", "Toyota", "Porsche", "Mercedes");

Создание карт и добавление к ним пар «ключ-значение» аналогично. Единственное отличие состоит в том, что мы передаем пары ключ и значение методуnewMapWith() как реализации интерфейсаPair.

Возьмем для примераUnifiedMap:

Pair pair1 = Tuples.pair(1, "One");
Pair pair2 = Tuples.pair(2, "Two");
Pair pair3 = Tuples.pair(3, "Three");

UnifiedMap map = new UnifiedMap<>(pair1, pair2, pair3);

Мы все еще можем использовать подход Java Collections API:

UnifiedMap map = new UnifiedMap<>();

map.put(1, "one");
map.put(2, "two");
map.put(3, "three");

Посколькуimmutable collections cannot be modified, they do not have implementations of methods that modify collections, напримерadd() иremove().

Неизменяемые коллекции, однако, позволяют нам вызывать эти методы, но в этом случае выдадутUnsupportedOperationException.

5. Получение элементов из коллекций

Так же, как при использовании стандартногоLists, элементы Eclipse CollectionsLists могут быть получены по их индексу:

list.get(0);

И значения карт Eclipse Collections можно получить с помощью их ключа:

map.get(0);

МетодыgetFirst() иgetLast() могут использоваться для получения первого и последнего элементов списка соответственно. В случае других коллекций они возвращают первый и последний элемент, который будет возвращен итератором.

map.getFirst();
map.getLast();

Методыmax() иmin() могут использоваться для получения максимального и минимального значений коллекции на основе естественного порядка.

map.max();
map.min();

6. Итерация по коллекции

Eclipse Collections предоставляет много способов перебора коллекций. Давайте посмотрим, что они из себя представляют и как работают на практике.

6.1. Коллекция Фильтрация

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

Вот пример:

@Test
public void givenListwhenSelect_thenCorrect() {
    MutableList greaterThanThirty = list
      .select(Predicates.greaterThan(30))
      .sortThis();

    Assertions.assertThat(greaterThanThirty)
      .containsExactly(31, 38, 41);
}

То же самое можно сделать с помощью простого лямбда-выражения:

return list.select(i -> i > 30)
  .sortThis();

Шаблон отклонения является противоположным. Он возвращает коллекцию всех элементов, которые не удовлетворяют логическому условию.

Давайте посмотрим на пример:

@Test
public void whenReject_thenCorrect() {
    MutableList notGreaterThanThirty = list
      .reject(Predicates.greaterThan(30))
      .sortThis();

    Assertions.assertThat(notGreaterThanThirty)
      .containsExactlyElementsOf(this.expectedList);
}

Здесь мы отклоняем все элементы, которые больше 30.

6.2. Методcollect()

Методcollect возвращает новую коллекцию, элементы которой являются результатами, возвращаемыми предоставленным лямбда-выражением - по сути, это комбинацияmap() иcollect() из Stream API.

Давайте посмотрим на это в действии:

@Test
public void whenCollect_thenCorrect() {
    Student student1 = new Student("John", "Hopkins");
    Student student2 = new Student("George", "Adams");

    MutableList students = FastList
      .newListWith(student1, student2);

    MutableList lastNames = students
      .collect(Student::getLastName);

    Assertions.assertThat(lastNames)
      .containsExactly("Hopkins", "Adams");
}

Созданная коллекцияlastNames содержит фамилии, которые собраны из спискаstudents.

Но,what if the returned collection is a collection of collections and we do not want to maintain a nested structure?

Например, если у каждого студента есть несколько адресов, и нам нужна коллекция, содержащая адреса в видеStrings, а не набор коллекций, мы можем использовать методflatCollect().

Вот пример:

@Test
public void whenFlatCollect_thenCorrect() {
    MutableList addresses = students
      .flatCollect(Student::getAddresses);

    Assertions.assertThat(addresses)
      .containsExactlyElementsOf(this.expectedAddresses);
}

6.3. Обнаружение элемента

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

Давайте быстро рассмотрим пример:

@Test
public void whenDetect_thenCorrect() {
    Integer result = list.detect(Predicates.greaterThan(30));

    Assertions.assertThat(result)
      .isEqualTo(41);
}

МетодanySatisfy определяет, удовлетворяет ли какой-либо элемент коллекции логическому условию.

Вот пример:

@Test
public void whenAnySatisfiesCondition_thenCorrect() {
    boolean result = list.anySatisfy(Predicates.greaterThan(30));

    assertTrue(result);
}

Точно так же методallSatisfy определяет, все ли элементы коллекции удовлетворяют логическому условию.

Давайте посмотрим на быстрый пример:

@Test
public void whenAnySatisfiesCondition_thenCorrect() {
    boolean result = list.allSatisfy(Predicates.greaterThan(0));

    assertTrue(result);
}

6.4. Методpartition()

Методpartition распределяет каждый элемент коллекции в одну из двух коллекций в зависимости от того, удовлетворяет ли элемент логическому условию.

Давайте посмотрим на пример:

@Test
public void whenAnySatisfiesCondition_thenCorrect() {
    MutableList numbers = list;
    PartitionMutableList partitionedFolks = numbers
      .partition(i -> i > 30);

    MutableList greaterThanThirty = partitionedFolks
      .getSelected()
      .sortThis();
    MutableList smallerThanThirty = partitionedFolks
      .getRejected()
      .sortThis();

    Assertions.assertThat(smallerThanThirty)
      .containsExactly(1, 5, 8, 17, 23);
    Assertions.assertThat(greaterThanThirty)
      .containsExactly(31, 38, 41);
}

6.5. Ленивая итерация

Ленивая итерация - это шаблон оптимизации, в котором вызывается метод итерации, но его фактическое выполнение откладывается до тех пор, пока другой последующий метод не потребует его действия или возвращаемых значений.

@Test
public void whenLazyIteration_thenCorrect() {
    Student student1 = new Student("John", "Hopkins");
    Student student2 = new Student("George", "Adams");
    Student student3 = new Student("Jennifer", "Rodriguez");

    MutableList students = Lists.mutable
      .with(student1, student2, student3);
    LazyIterable lazyStudents = students.asLazy();
    LazyIterable lastNames = lazyStudents
      .collect(Student::getLastName);

    Assertions.assertThat(lastNames)
      .containsAll(Lists.mutable.with("Hopkins", "Adams", "Rodriguez"));
}

Здесь объектlazyStudents не получает элементы спискаstudents, пока не будет вызван методcollect().

7. Сопряжение элементов коллекции

Методzip() возвращает новую коллекцию, объединяя элементы двух коллекций в пары. Если какая-либо из двух коллекций длиннее, остальные элементы будут усечены.

Давайте посмотрим, как мы можем это использовать:

@Test
public void whenZip_thenCorrect() {
    MutableList numbers = Lists.mutable
      .with("1", "2", "3", "Ignored");
    MutableList cars = Lists.mutable
      .with("Porsche", "Volvo", "Toyota");
    MutableList> pairs = numbers.zip(cars);

    Assertions.assertThat(pairs)
      .containsExactlyElementsOf(this.expectedPairs);
}

Мы также можем связать элементы коллекции с их индексами, используя методzipWithIndex():

@Test
public void whenZip_thenCorrect() {
    MutableList cars = FastList
      .newListWith("Porsche", "Volvo", "Toyota");
    MutableList> pairs = cars.zipWithIndex();

    Assertions.assertThat(pairs)
      .containsExactlyElementsOf(this.expectedPairs);
}

8. Преобразование коллекций

Eclipse Collections предоставляет простые методы для преобразования типа контейнера в другой. Это методыtoList(),toSet(),toBag() иtoMap().

Давайте посмотрим, как мы можем их использовать:

public static List convertToList() {
    UnifiedSet cars = new UnifiedSet<>();

    cars.add("Toyota");
    cars.add("Mercedes");
    cars.add("Volkswagen");

    return cars.toList();
}

Давайте запустим наш тест:

@Test
public void whenConvertContainerToAnother_thenCorrect() {
    MutableList cars = (MutableList) ConvertContainerToAnother
      .convertToList();

    Assertions.assertThat(cars)
      .containsExactlyElementsOf(
      FastList.newListWith("Volkswagen", "Toyota", "Mercedes"));
}

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

В этом руководстве мы рассмотрели краткий обзор коллекций Eclipse и функций, которые они предоставляют.

Полная реализация этого руководства доступнаover on GitHub.