目录
- 前言
- 一、引入依赖
- [二、Range 的各种区间](#二、Range 的各种区间)
-
- [1. 闭区间 a,b](#1. 闭区间 [a,b])
- [2. 开区间 (a,b)](#2. 开区间 (a,b))
- [3. 左开右闭 (a,b]](#3. 左开右闭 (a,b])
- [4. 左闭右开 [a,b)](#4. 左闭右开 [a,b))
- 三、无穷区间
- 四、判断元素是否在区间内
- 五、判断一个区间是否包含另一个区间
- 六、区间交集
- 七、区间并集
- 八、判断两个区间是否有重叠
- 九、获取边界值
- [十、LocalDate 处理示例](#十、LocalDate 处理示例)
- 总结
前言
com.google.common.collect.Range 是 Guava(Google Guava)集合工具库 中的一个类,用来表示一个连续区间(Range)。
它最大的作用就是:
用对象的方式描述区间范围,而不是自己写一堆
>=、<=、>、<判断。
例如:
java
年龄 >= 18 && 年龄 <= 60
可以写成:
java
Range<Integer> range = Range.closed(18, 60);
range.contains(20); // true
range.contains(70); // false
一、引入依赖
Maven:
xml
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.2.1-jre</version>
</dependency>
导包:
java
import com.google.common.collect.Range;
二、Range 的各种区间
1. 闭区间 a,b
包含左右边界
java
Range<Integer> range = Range.closed(1, 10);
等价于:
java
1 <= x <= 10
测试:
java
range.contains(1); // true
range.contains(10); // true
range.contains(5); // true
2. 开区间 (a,b)
不包含左右边界
java
Range<Integer> range = Range.open(1, 10);
等价于:
java
1 < x < 10
测试:
java
range.contains(1); // false
range.contains(10); // false
range.contains(5); // true
3. 左开右闭 (a,b]
java
Range<Integer> range = Range.openClosed(1, 10);
等价于:
java
1 < x <= 10
4. 左闭右开 [a,b)
java
Range<Integer> range = Range.closedOpen(1, 10);
等价于:
java
1 <= x < 10
三、无穷区间
1.大于
java
Range<Integer> range = Range.greaterThan(10);
等价:
java
x > 10
2.大于等于
java
Range<Integer> range = Range.atLeast(10);
等价:
java
x >= 10
3.小于
java
Range<Integer> range = Range.lessThan(10);
等价:
java
x < 10
4.小于等于
java
Range<Integer> range = Range.atMost(10);
等价:
java
x <= 10
4.全部范围
java
Range<Integer> range = Range.all();
等价:
java
(-∞,+∞)
四、判断元素是否在区间内
最常用的方法:
java
contains()
例如:
java
Range<Integer> range = Range.closed(1, 100);
System.out.println(range.contains(50));
输出:
java
true
五、判断一个区间是否包含另一个区间
java
Range<Integer> range1 = Range.closed(1, 100);
Range<Integer> range2 = Range.closed(20, 50);
System.out.println(range1.encloses(range2));
输出:
java
true
因为:
text
[1,100] 完全包含 [20,50]
六、区间交集
假设:
java
[1,10]
[5,15]
求交集:
java
Range<Integer> r1 = Range.closed(1,10);
Range<Integer> r2 = Range.closed(5,15);
Range<Integer> intersection = r1.intersection(r2);
System.out.println(intersection);
输出:
java
[5..10]
七、区间并集
java
Range<Integer> r1 = Range.closed(1,10);
Range<Integer> r2 = Range.closed(5,15);
Range<Integer> span = r1.span(r2);
System.out.println(span);
输出:
java
[1..15]
八、判断两个区间是否有重叠
java
Range<Integer> r1 = Range.closed(1,10);
Range<Integer> r2 = Range.closed(5,15);
boolean connected = r1.isConnected(r2);
结果:
java
true
因为:
text
[1,10]
[5,15]
有公共部分。
如果:
java
Range<Integer> r1 = Range.closed(1,10);
Range<Integer> r2 = Range.closed(20,30);
r1.isConnected(r2);
结果:
java
false
九、获取边界值
java
Range<Integer> range = Range.closed(10,20);
获取下界:
java
range.lowerEndpoint();
结果:
java
10
获取上界:
java
range.upperEndpoint();
结果:
java
20
十、LocalDate 处理示例
对于 Range<LocalDate>,Guava 原生提供了:
- 交集
- 并集
但是:
- 差集没有直接提供
因为两个区间相减后可能得到 0个、1个或2个区间 ,结果不再是一个单独的 Range。
1.交集
假设:
tex
A = [2026-01-01,2026-03-31]
B = [2026-02-01,2026-04-30]
图示:
tex
A: 2026-01-01 -------------------- 2026-03-31
B: 2026-02-01 -------------------- 2026-04-30
交集:
tex
[2026-02-01,2026-03-31]
代码:
java
Range<LocalDate> a = Range.closed(LocalDate.of(2026, 1, 1), LocalDate.of(2026, 3, 31));
Range<LocalDate> b = Range.closed(LocalDate.of(2026, 2, 1), LocalDate.of(2026, 4, 30));
Range<LocalDate> intersection = a.intersection(b);
System.out.println(intersection);
输出:
tex
[2026-02-01..2026-03-31]
2.并集
还是上面的两个区间:
tex
A = [2026-01-01,2026-03-31]
B = [2026-02-01,2026-04-30]
并集:
tex
[2026-01-01,2026-04-30]
代码:
java
Range<LocalDate> a = Range.closed(LocalDate.of(2026, 1, 1), LocalDate.of(2026, 3, 31));
Range<LocalDate> b = Range.closed(LocalDate.of(2026, 2, 1), LocalDate.of(2026, 4, 30));
Range<LocalDate> union = a.span(b);
System.out.println(union);
输出:
tex
[2026-01-01..2026-04-30]
注意
求并集使用span() 时不要求区间重叠。
例如:
java
Range<LocalDate> a = Range.closed(LocalDate.of(2026,1,1), LocalDate.of(2026,1,31));
Range<LocalDate> b = Range.closed(LocalDate.of(2026,3,1), LocalDate.of(2026,3,31));
Range<LocalDate> union = a.span(b);
System.out.println(union);
结果:
tex
[2026-01-01..2026-03-31]
即使中间二月份是空的。
3.差集(A - B)
假设:
tex
A = [2026-01-01,2026-03-31]
B = [2026-02-01,2026-02-28]
图示:
tex
A:
|-----------------------------|
B:
|-----------|
差集:
tex
[2026-01-01,2026-01-31]
[2026-03-01,2026-03-31]
结果变成两个区间。
代码:
java
public class MainServer {
public static void main(String[] args) throws Exception {
Range<LocalDate> a = Range.closed(LocalDate.of(2026,1,1), LocalDate.of(2026,3,31));
Range<LocalDate> b = Range.closed(LocalDate.of(2026,2,1), LocalDate.of(2026,2,28));
List<Range<LocalDate>> result = subtract(a, b);
result.forEach(System.out::println);
}
public static List<Range<LocalDate>> subtract(Range<LocalDate> source, Range<LocalDate> remove) {
List<Range<LocalDate>> result = new ArrayList<>();
if (!source.isConnected(remove)) {
result.add(source);
return result;
}
Range<LocalDate> intersection = source.intersection(remove);
// 左边剩余部分
if (source.lowerEndpoint().isBefore(intersection.lowerEndpoint())) {
result.add(
Range.closed(source.lowerEndpoint(), intersection.lowerEndpoint().minusDays(1)));
}
// 右边剩余部分
if (source.upperEndpoint().isAfter(intersection.upperEndpoint())) {
result.add(
Range.closed(intersection.upperEndpoint().plusDays(1), source.upperEndpoint()));
}
return result;
}
}
输出:
java
[2026-01-01..2026-01-31]
[2026-03-01..2026-03-31]
总结
Range<T> 本质上就是:
java
把
x > 1
x >= 1
1 <= x <= 10
5 < x < 20
这种范围条件封装成对象
最常用的方法:
java
Range.closed(a,b) // [a,b]
Range.open(a,b) // (a,b)
Range.atLeast(a) // >=a
Range.atMost(a) // <=a
contains(x) // 判断值是否在范围内
lowerEndpoint() // 下界
upperEndpoint() // 上界
intersection() // 交集
span() // 并集
isConnected() // 是否重叠
encloses() // 是否包含