Перейти к основному содержимому

Путеводитель по гуаве RangeMap

· 4 мин. чтения

1. Обзор

В этом руководстве мы покажем, как использовать интерфейс RangeMap Google Guava и его реализации.

RangeMap — это особый вид сопоставления непересекающихся непустых диапазонов с ненулевыми значениями. Используя запросы, мы можем найти значение для любого конкретного диапазона на этой карте.

Базовой реализацией RangeMap является TreeRangeMap . Внутри карта использует TreeMap для хранения ключа в виде диапазона и значения в виде любого пользовательского объекта Java.

2. RangeMap Google Guava

Давайте посмотрим, как использовать класс RangeMap .

2.1. Зависимость от Maven

Начнем с добавления зависимости библиотеки Google Guava в pom.xml :

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>

Последнюю версию зависимости можно проверить здесь .

3. Создание

Вот некоторые из способов, которыми мы можем создать экземпляр RangeMap :

  • Используйте метод create из класса TreeRangeMap для создания изменяемой карты:
RangeMap<Integer, String> experienceRangeDesignationMap
= TreeRangeMap.create();
  • Если мы намерены создать неизменяемую карту диапазона, используйте класс ImmutableRangeMap (который следует шаблону построителя):
RangeMap<Integer, String> experienceRangeDesignationMap
= new ImmutableRangeMap.<Integer, String>builder()
.put(Range.closed(0, 2), "Associate")
.build();

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

Давайте начнем с простого примера, показывающего использование RangeMap .

4.1. Поиск на основе ввода в пределах диапазона

Мы можем получить значение, связанное со значением в диапазоне целых чисел:

@Test
public void givenRangeMap_whenQueryWithinRange_returnsSucessfully() {
RangeMap<Integer, String> experienceRangeDesignationMap
= TreeRangeMap.create();

experienceRangeDesignationMap.put(
Range.closed(0, 2), "Associate");
experienceRangeDesignationMap.put(
Range.closed(3, 5), "Senior Associate");
experienceRangeDesignationMap.put(
Range.closed(6, 8), "Vice President");
experienceRangeDesignationMap.put(
Range.closed(9, 15), "Executive Director");

assertEquals("Vice President",
experienceRangeDesignationMap.get(6));
assertEquals("Executive Director",
experienceRangeDesignationMap.get(15));
}

Примечание:

  • Закрытый метод класса Range предполагает, что диапазон целочисленных значений находится в диапазоне от 0 до 2 (оба включительно).
  • Диапазон в приведенном выше примере состоит из целых чисел. Мы можем использовать диапазон любого типа, если он реализует интерфейс Comparable , такой как String , Character , десятичные числа с плавающей запятой и т. д.
  • RangeMap возвращает Null , когда мы пытаемся получить значение для диапазона, которого нет на карте.
  • В случае ImmutableRangeMap диапазон одного ключа не может перекрываться диапазоном ключа, который необходимо вставить. Если это произойдет, мы получим исключение IllegalArgumentException .
  • И ключи, и значения в RangeMap не могут быть нулевыми . Если любой из них равен нулю, мы получаем исключение NullPointerException .

4.2. Удаление значения на основе диапазона

Давайте посмотрим, как мы можем удалить значения. В этом примере мы покажем, как удалить значение, связанное со всем диапазоном. Мы также покажем, как удалить значение на основе частичного диапазона ключей:

@Test
public void givenRangeMap_whenRemoveRangeIsCalled_removesSucessfully() {
RangeMap<Integer, String> experienceRangeDesignationMap
= TreeRangeMap.create();

experienceRangeDesignationMap.put(
Range.closed(0, 2), "Associate");
experienceRangeDesignationMap.put(
Range.closed(3, 5), "Senior Associate");
experienceRangeDesignationMap.put(
Range.closed(6, 8), "Vice President");
experienceRangeDesignationMap.put(
Range.closed(9, 15), "Executive Director");

experienceRangeDesignationMap.remove(Range.closed(9, 15));
experienceRangeDesignationMap.remove(Range.closed(1, 4));

assertNull(experienceRangeDesignationMap.get(9));
assertEquals("Associate",
experienceRangeDesignationMap.get(0));
assertEquals("Senior Associate",
experienceRangeDesignationMap.get(5));
assertNull(experienceRangeDesignationMap.get(1));
}

Как видно, даже после частичного удаления значений из диапазона мы все равно можем получить значения, если диапазон все еще действителен.

4.3. Диапазон ключевого диапазона

Если мы хотим узнать, каков общий диапазон RangeMap , мы можем использовать метод span :

@Test
public void givenRangeMap_whenSpanIsCalled_returnsSucessfully() {
RangeMap<Integer, String> experienceRangeDesignationMap = TreeRangeMap.create();
experienceRangeDesignationMap.put(Range.closed(0, 2), "Associate");
experienceRangeDesignationMap.put(Range.closed(3, 5), "Senior Associate");
experienceRangeDesignationMap.put(Range.closed(6, 8), "Vice President");
experienceRangeDesignationMap.put(Range.closed(9, 15), "Executive Director");
experienceRangeDesignationMap.put(Range.closed(16, 30), "Managing Director");
Range<Integer> experienceSpan = experienceRangeDesignationMap.span();

assertEquals(0, experienceSpan.lowerEndpoint().intValue());
assertEquals(30, experienceSpan.upperEndpoint().intValue());
}

4.4. Получение SubRangeMap

Когда мы хотим выбрать часть из RangeMap , мы можем использовать метод subRangeMap :

@Test
public void givenRangeMap_whenSubRangeMapIsCalled_returnsSubRangeSuccessfully() {
RangeMap<Integer, String> experienceRangeDesignationMap = TreeRangeMap.create();

experienceRangeDesignationMap
.put(Range.closed(0, 2), "Associate");
experienceRangeDesignationMap
.put(Range.closed(3, 5), "Senior Associate");
experienceRangeDesignationMap
.put(Range.closed(6, 8), "Vice President");
experienceRangeDesignationMap
.put(Range.closed(8, 15), "Executive Director");
experienceRangeDesignationMap
.put(Range.closed(16, 30), "Managing Director");
RangeMap<Integer, String> experiencedSubRangeDesignationMap
= experienceRangeDesignationMap.subRangeMap(Range.closed(4, 14));

assertNull(experiencedSubRangeDesignationMap.get(3));
assertTrue(experiencedSubRangeDesignationMap.asMapOfRanges().values()
.containsAll(Arrays.asList("Executive Director", "Vice President", "Executive Director")));
}

Этот метод возвращает пересечение RangeMap с заданным параметром Range .

4.5. Получение записи

Наконец, если мы ищем Entry из RangeMap , мы используем метод getEntry :

@Test
public void givenRangeMap_whenGetEntryIsCalled_returnsEntrySucessfully() {
RangeMap<Integer, String> experienceRangeDesignationMap
= TreeRangeMap.create();

experienceRangeDesignationMap.put(
Range.closed(0, 2), "Associate");
experienceRangeDesignationMap.put(
Range.closed(3, 5), "Senior Associate");
experienceRangeDesignationMap.put(
Range.closed(6, 8), "Vice President");
experienceRangeDesignationMap.put(
Range.closed(9, 15), "Executive Director");
Map.Entry<Range<Integer>, String> experienceEntry
= experienceRangeDesignationMap.getEntry(10);

assertEquals(Range.closed(9, 15), experienceEntry.getKey());
assertEquals("Executive Director", experienceEntry.getValue());
}

5. Вывод

В этом руководстве мы проиллюстрировали примеры использования RangeMap в библиотеке Guava. Он преимущественно используется для получения значения на основе ключа, указанного как a из карты.

Реализацию этих примеров можно найти в проекте GitHub — это проект на основе Maven, поэтому его легко импортировать и запускать как есть.