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, поэтому его легко импортировать и запускать как есть.