If you’re working with Spring, check out "REST With Spring":

>> CHECK OUT THE COURSE

1. Overview

In this tutorial, we’ll show how to use the Google Guava’s RangeSet interface and its implementations.

A RangeSet is a set comprising of zero or more non-empty, disconnected ranges. When adding a range to a mutable RangeSet, any connected ranges are merged together while empty ranges are ignored.

The basic implementation of RangeSet is a TreeRangeSet.

2. Google Guava’s RangeSet

Let’s have a look at how to use the RangeSet class.

2.1. Maven Dependency

Let’s start by adding Google’s Guava library dependency in the pom.xml:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>21.0</version>
</dependency>

The latest version of the dependency can be checked here.

3. Creation

Let’s explore some of the ways in which we can create an instance of RangeSet.

First, we can use the create method from the class TreeRangeSet to create a mutable set:

RangeSet<Integer> numberRangeSet = TreeRangeSet.create();

If we already have collections in place, use the create method from the class TreeRangeSet to create a mutable set by passing that collection:

List<Range<Integer>> numberList = Arrays.asList(Range.closed(0, 2));
RangeSet<Integer> numberRangeSet = TreeRangeSet.create(numberList);

Finally, if we need to create an immutable range set, use the ImmutableRangeSet class (creating which follows a builder pattern):

RangeSet<Integer> numberRangeSet 
  = new ImmutableRangeSet.<Integer>builder().add(Range.closed(0, 2)).build();

4. Usage

Let’s start with a simple example that shows the usage of RangeSet.

4.1. Adding to a Range

We can check whether the input supplied is within a range present in any of the range items in a set:

@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));
}

Notes:

  • The closed method of the Range class assumes the range of integer values to be between 0 to 2 (both inclusive)
  • The Range in above example consists of integers. We can use a range consisting of any type as long as it implements the Comparable interface such as String, Character, floating point decimals etc
  • In the case of an ImmutableRangeSet, a range item present in the set cannot overlap with a range item that one would like to add. If that happens, we get an IllegalArgumentException
  • Range input to a RangeSet cannot be null. If the input is null, we will get a NullPointerException

4.2. Removing a Range

Let’s see how we can remove values from a 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));
}

As can be seen, after removal we can still access values present in any of the range items left in the set.

4.3. Range Span

Let’s now see what the overall span of a RangeSet is:

@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. Getting a Subrange

If we wish to get part of RangeSet based on a given Range, we can use the subRangeSet method:

@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 Method

Next, let’s get all the values except the one present in RangeSet, using the complement method:

@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. Intersection with a Range

Finally, when we would like to check whether a range interval present in RangeSet intersects with some or all the values in another given range, we can make use of the intersect method:

@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. Conclusion

In this tutorial, we illustrated the RangeSet of the Guava library using some examples. The RangeSet is predominantly used to check whether a value falls within a certain range present in the set.

The implementation of these examples can be found in the GitHub project – this is a Maven-based project, so it should be easy to import and run as is.

The new Certification Class of "REST With Spring" is finally out:

>> CHECK OUT THE COURSE