概述
在这个教程中,我们将展示如何使用Google Guava库中的RangeMap
接口及其实现。
RangeMap
是一种特殊的映射,它将不重叠的非空区间映射到非空值。通过查询,我们可以查找映射中任何特定区间的值。
2. Google Guava的RangeMap
2.1. Maven依赖
首先,在pom.xml
文件中添加Google Guava库的依赖:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.3-jre</version>
</dependency>
最新的依赖版本可以在这里查看。
3. 创建
创建RangeMap
实例的方式有几种:
- 使用
TreeRangeMap
类的create
方法创建可变映射:
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
类的closed
方法假定整数区间的范围是0到2(包括两者)。- 上述示例中的
Range
包含整数。我们可以使用任何类型的区间,只要它们实现了Comparable
接口,如String
、Character
、浮点数等。 - 当尝试获取地图中不存在的区间值时,
RangeMap
返回null
。 - 对于不可变的
ImmutableRangeMap
,一个键的区间不能与需要插入的键的区间重叠。如果发生这种情况,会抛出IllegalArgumentException
。 RangeMap
中的键和值都不能为null
。如果其中任何一个为null
,将抛出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. 获取子区间映射
当我们想从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")));
}
此方法返回给定Range
参数与RangeMap
的交集。
4.5. 获取条目
最后,如果我们想要从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. 总结
在这篇教程中,我们展示了在Guava库中使用RangeMap
的一些例子。它主要用于根据指定的键从映射中获取值。
这些示例的实现可以在GitHub项目中找到——这是一个基于Maven的项目,可以直接导入并运行。