1. 概述
在这个教程中,我们将展示如何使用Google Guava的RangeSet
接口及其实现。
RangeSet
是一个包含零个或多个不相连的非空范围的集合。在向可变的RangeSet
中添加范围时,任何相连的范围会被合并,而空范围则被忽略。
RangeSet
的基本实现是TreeRangeSet
。
2. Google Guava的RangeSet
让我们来看看如何使用RangeSet
类。
2.1. Maven依赖
首先,在pom.xml
中添加Google Guava库的依赖:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.3-jre</version>
</dependency>
最新的依赖版本可以在这里查看。
3. 创建
接下来,我们探索一些创建RangeSet
实例的方法。
首先,我们可以使用TreeRangeSet
类的create
方法创建一个可变的集合:
RangeSet<Integer> numberRangeSet = TreeRangeSet.create();
如果我们已经有了集合,可以使用TreeRangeSet
类的create
方法,通过传递该集合来创建一个可变的集合:
List<Range<Integer>> numberList = Arrays.asList(Range.closed(0, 2));
RangeSet<Integer> numberRangeSet = TreeRangeSet.create(numberList);
最后,如果我们需要创建一个不可变的范围集,可以使用ImmutableRangeSet
类(其创建遵循构建者模式):
RangeSet<Integer> numberRangeSet
= new ImmutableRangeSet.<Integer>builder().add(Range.closed(0, 2)).build();
4. 使用
现在,我们从一个简单的示例开始,展示RangeSet
的用法。
4.1. 添加到范围
我们可以检查输入是否位于集合中任何一个范围项内的范围内:
@Test
public void givenRangeSet_whenQueryWithinRange_returnsSucessfully() {
RangeSet<Integer> numberRangeSet = TreeRangeSet.create();
numberRangeSet.add(Range.closed(0, 2));
numberRangeSet.add(Range.closed(3, 5));
numberRangeSet.add(Range.closed(6, 8));
assertTrue(numberRangeSet.contains(1));
assertFalse(numberRangeSet.contains(9));
}
注意:
-
Range
类的closed
方法假设整数范围为0到2(包括两端) - 上述示例中的
Range
包含整数。只要实现了Comparable
接口的类型(如String
、Character
、浮点数等)都可以作为范围使用 - 对于不可变的
ImmutableRangeSet
,集合中的范围项不能与想要添加的范围项重叠。如果发生这种情况,会抛出IllegalArgumentException
- 将范围输入到
RangeSet
中不能为null
。如果输入为null
,将抛出NullPointerException
4.2. 删除范围
让我们看看如何从RangeSet
中删除值:
@Test
public void givenRangeSet_whenRemoveRangeIsCalled_removesSucessfully() {
RangeSet<Integer> numberRangeSet = TreeRangeSet.create();
numberRangeSet.add(Range.closed(0, 2));
numberRangeSet.add(Range.closed(3, 5));
numberRangeSet.add(Range.closed(6, 8));
numberRangeSet.add(Range.closed(9, 15));
numberRangeSet.remove(Range.closed(3, 5));
numberRangeSet.remove(Range.closed(7, 10));
assertTrue(numberRangeSet.contains(1));
assertFalse(numberRangeSet.contains(9));
assertTrue(numberRangeSet.contains(12));
}
如图所示,删除后,我们仍然可以访问集合中剩下的任何范围项内的值。
4.3. 范围跨度
现在,让我们看看RangeSet
的整体跨度:
@Test
public void givenRangeSet_whenSpanIsCalled_returnsSucessfully() {
RangeSet<Integer> numberRangeSet = TreeRangeSet.create();
numberRangeSet.add(Range.closed(0, 2));
numberRangeSet.add(Range.closed(3, 5));
numberRangeSet.add(Range.closed(6, 8));
Range<Integer> experienceSpan = numberRangeSet.span();
assertEquals(0, experienceSpan.lowerEndpoint().intValue());
assertEquals(8, experienceSpan.upperEndpoint().intValue());
}
4.4. 获取子范围
如果我们想根据给定的范围获取RangeSet
的一部分,可以使用subRangeSet
方法:
@Test
public void
givenRangeSet_whenSubRangeSetIsCalled_returnsSubRangeSucessfully() {
RangeSet<Integer> numberRangeSet = TreeRangeSet.create();
numberRangeSet.add(Range.closed(0, 2));
numberRangeSet.add(Range.closed(3, 5));
numberRangeSet.add(Range.closed(6, 8));
RangeSet<Integer> numberSubRangeSet
= numberRangeSet.subRangeSet(Range.closed(4, 14));
assertFalse(numberSubRangeSet.contains(3));
assertFalse(numberSubRangeSet.contains(14));
assertTrue(numberSubRangeSet.contains(7));
}
4.5. 补集方法
接下来,我们使用complement
方法获取除RangeSet
中存在的所有值之外的值:
@Test
public void givenRangeSet_whenComplementIsCalled_returnsSucessfully() {
RangeSet<Integer> numberRangeSet = TreeRangeSet.create();
numberRangeSet.add(Range.closed(0, 2));
numberRangeSet.add(Range.closed(3, 5));
numberRangeSet.add(Range.closed(6, 8));
RangeSet<Integer> numberRangeComplementSet
= numberRangeSet.complement();
assertTrue(numberRangeComplementSet.contains(-1000));
assertFalse(numberRangeComplementSet.contains(2));
assertFalse(numberRangeComplementSet.contains(3));
assertTrue(numberRangeComplementSet.contains(1000));
}
4.6. 与范围的交集
最后,当我们想检查RangeSet
中是否存在与给定范围的部分或全部值相交的情况时,可以使用intersect
方法:
@Test
public void givenRangeSet_whenIntersectsWithinRange_returnsSucessfully() {
RangeSet<Integer> numberRangeSet = TreeRangeSet.create();
numberRangeSet.add(Range.closed(0, 2));
numberRangeSet.add(Range.closed(3, 10));
numberRangeSet.add(Range.closed(15, 18));
assertTrue(numberRangeSet.intersects(Range.closed(4, 17)));
assertFalse(numberRangeSet.intersects(Range.closed(19, 200)));
}
5. 总结
在这篇教程中,我们通过一些示例展示了Guava库中的RangeSet
。RangeSet
主要用于检查一个值是否落在集合中的特定范围内。
这些示例的实现可以在GitHub项目中找到——这是一个基于Maven的项目,可以直接导入并运行。