Guava工具集-Range范围区间工具类

概述

最近在做规则校验,未避免不正常的数据出现,需要做范围校验。找了部分工具类,工具类能够支撑的较少,最后选择了Guava的Range类实现范围校验。可以计算区间是否连接,取交集,并集等操作。

Guava工具集-Range范围区间工具类_第1张图片

Rang类使用

pom.xml

Maven repository:https://mvnrepository.com/artifact/com.google.guava/guava

  <dependency>
      <groupId>com.google.guavagroupId>
      <artifactId>guavaartifactId>
      <version>31.0.1-jreversion>
  dependency>

注意:
guava版本号小于30.0-jre的存在安全漏洞

️代码示例

 public static void main(String[] args) {
        // [1,2] 全部闭区间
        Range<Integer> one = Range.closed(1, 2);
        System.out.println(one);
        // [2,5) 左闭右开
        Range<Integer> two = Range.closedOpen(2, 5);
        System.out.println(two);

        // (2,5) 全部开区间
        Range<Integer> three = Range.open(2, 5);
        System.out.println(three);

        // (2,5] 左开右闭
        Range<Integer> four = Range.closedOpen(2, 5);
        System.out.println(four);

        // (6,10] 左开右闭
        Range<Integer> five = Range.closedOpen(6, 10);
        System.out.println(five);

        // (6..+∞)
        Range<Integer> six = Range.greaterThan(6);
        System.out.println(six);


        // 区间是否连接
        // 如果存在一个 (可能为空) 范围,则返回true ,该范围由该范围和其他包围。
        // 例如,
        // [2,4) 和 [5,7) 未连接
        // [2,4) 和 [3,5) 是连接的,因为两者都包围了 [3,4)
        // [2,4) 和 [4,6) 是连接的,因为两者都包围了空范围 [4,4)
        // 请注意,当且仅当此方法返回true时,此范围和其他具有定义明确的union和intersection (作为单个,可能为空的范围)。
        // 连通性关系既是自反的又是对称的,但由于它不是传递的,因此不会形成等价关系。
        // 请注意,即使 “在它们之间” 没有元素,某些离散范围也不被认为是连通的。例如, [3,5] 不被视为与 [6,10] 相连。在这些情况下,可能希望在测试连接性之前用规范 (离散域) 对两个输入范围进行预处理。
        boolean connected = one.isConnected(two);
        System.out.println(one + "和" + two + "is connected:" + connected);

        //返回包含该范围和其他的最小范围。例如, [1 .. 3] 和 (5..7) 的跨度为 [1..7)。
        // 如果输入范围为connected ,则返回的范围也可以称为union。如果不是,请注意,span可能包含两个输入范围中未包含的值。
        // 和交集一样,这个操作是可交换的,结合的,幂等的。与它不同,它总是为任何两个输入范围定义良好。
        // 并集
        Range<Integer> span = one.span(two);
        System.out.println(one + "和" + two + "并集为:" + span);

        //
        Range<Integer> span2 = four.span(five);
        System.out.println(four + "和" + five + "并集为:" + span2);

        // 交集
        //如果存在该范围,则返回该范围和connectedRange包围的最大范围。
        // 例如, [1 .. 5] 和 (3..7) 的交集为 (3 .. 5] 。结果范围可能为空; 例如, [1..5) 与 [5..7) 相交产生 [5..5) 的空范围。
        // 当且仅当两个范围连通时,交点才存在。
        // 交集运算为可交换、结合和幂等,其单位元为all )。
        // 投掷:
        // IllegalArgumentException -如果isConnected(connectedRange) 为false
        Range<Integer> integerRange = one.intersection(two);
        System.out.println(one + "和" + two + "交集为:" + integerRange);

    }
[1..2]
[2..5)
(2..5)
[2..5)
[6..10)
(6..+)
[1..2][2..5)is connected:true
[1..2][2..5)并集为:[1..5)
[2..5)[6..10)并集为:[2..10)
[1..2][2..5)交集为:[2..2]

注意:
Range类的方法包含了空范围的场景,例如:[3,3),在具体使用时,需要根据实际场景做进一步处理

Rang类详解

上边通过简单的例子说明了Range类的简单使用,接下来对Range类详细方法做一个说明。

Range构建

Guava中的Range要求上端点不能小于下端点,否者会抛出IllegalArgumentException异常,上下端点可能是相等的(可能存在空区间的场景)。
Range的区间是闭区间或半开半闭区间(至少有一个端点是包含在区间中),比如:

  • [5..5]:单元素区间
  • [5..5); (5..5]:空区间,但它们是有效的
  • (5..5):无效区间

Guava提供了BoundType枚举类来指定区间边界的类型,包含 CLOSED 和 OPEN 两个值。

  • 有界区间 : range(C, BoundType, C, BoundType)
  • 无上界区间:((a..+∞) 或[a..+∞)) downTo(C, BoundType)
  • 无下界区间:((-∞..b) 或(-∞..b]) upTo(C, BoundType)
System.out.println(Range.open(1, 2));  //(1..2)
System.out.println(Range.closed(1, 2));  // [1..2]
System.out.println(Range.closedOpen(1, 2));  // [1..2)
System.out.println(Range.openClosed(1, 2));  // (1..2]
System.out.println(Range.greaterThan(1));  // (1..+∞)
System.out.println(Range.atLeast(1));  // [1..+∞)
System.out.println(Range.lessThan(2));  // (-∞..2)
System.out.println(Range.atMost(2));  // (-∞..2]
System.out.println(Range.range(1, BoundType.CLOSED, 2, BoundType.OPEN));  // [1..2)
System.out.println(Range.downTo(5, BoundType.OPEN));  // (5..+∞)
System.out.println(Range.upTo(5, BoundType.CLOSED));  // (-∞..5]

️区间运算

contains——包含运算

判断区间是否包含某个值

boolean contains = Range.closed(2, 10).contains(3);
System.out.println(contains);//true

查询运算

Range 类提供了以下方法来查看区间的端点:

  • hasLowerBound()hasUpperBound():判断区间是否有特定边界,或是无限的;
  • lowerBoundType()upperBoundType():返回区间边界类型,CLOSEDOPEN;如果区间没有对应的边界,抛出 IllegalStateException
  • lowerEndpoint()upperEndpoint():返回区间的端点值;如果区间没有对应的边界,抛出 IllegalStateException
  • isEmpty():判断是否为空区间。
Range.closedOpen(4, 4).isEmpty(); // returns true
Range.openClosed(4, 4).isEmpty(); // returns true
Range.closed(4, 4).isEmpty(); // returns false
Range.open(4, 4).isEmpty(); // Range.open throws IllegalArgumentException
Range.closed(3, 10).lowerEndpoint(); // returns 3
Range.open(3, 10).lowerEndpoint(); // returns 3
Range.closed(3, 10).lowerBoundType(); // returns CLOSED
Range.open(3, 10).upperBoundType(); // returns OPEN

System.out.println(Range.open(3, 10).hasLowerBound());//(3,10) true
System.out.println(Range.atMost( 10).hasLowerBound()); //(-∞,10) false
System.out.println(Range.atLeast( 10).hasLowerBound()); //(10,+∞) true
System.out.println(Range.atLeast( 10).hasUpperBound()); //(10,+∞) false

☘️关系运算-包含

区间之间的最基本关系就是包含encloses(Range)
如果内区间的边界没有超出外区间的边界,则外区间包含内区间。包含判断的结果完全取决于区间端点的比较

// [3..6] 包含[4..5] ;
System.out.println(Range.closed(3,6).encloses(Range.closed(4,5)));//true
// (3..6) 包含(3..6) ;
System.out.println(Range.open(3,6).encloses(Range.open(3,6)));//true
// [3..6] 包含[4..4),虽然后者是空区间;
System.out.println(Range.closed(3,6).encloses(Range.closedOpen(4,4)));//true
// (3..6]不包含[3..6] ;
System.out.println(Range.openClosed(3,6).encloses(Range.closed(3,6)));//false
// [4..5]不包含(3..6)
System.out.println(Range.closed(4,5).encloses(Range.open(3,6)));//false

☕️关系运算-相连

Range.isConnected(Range)判断区间是否是相连的。isConnected 测试是否有区间同时包含于这两个区间,这等同于数学上的定义”两个区间的并集是连续集合的形式”(空区间的特殊情况除外)。

System.out.println(Range.closed(3,5).isConnected(Range.open(5,10)));//true
System.out.println(Range.closed(0,9).isConnected(Range.closed(3,4)));//true
System.out.println(Range.closed(0,5).isConnected(Range.closed(3,9)));//true
System.out.println(Range.open(3,5).isConnected(Range.open(5,10)));//false
System.out.println(Range.closed(1,5).isConnected(Range.closed(6,10)));//false
// 注意空区间形式
System.out.println(Range.openClosed(5,5).isConnected(Range.closedOpen(5,5)));//false

关系运算-交集

Range.intersection(Range)返回两个区间的交集:既包含于第一个区间,又包含于另一个区间的最大区间。
**当且仅当两个区间是相连的,它们才有交集。**如果两个区间没有交集,该方法将抛出 IllegalArgumentException。使用前可以先校验是否是相连的。

System.out.println(Range.closed(3,5).intersection(Range.closed(4,6)));//[4..5]

关系运算-并集

Range.span(Range)返回”同时包括两个区间的最小区间“,如果两个区间相连,那就是它们的并集。

    System.out.println(Range.closed(3,5).span(Range.closed(7,9)));//[3..9]
    System.out.println(Range.closed(3,5).span(Range.closed(4,8)));//[3..8]

参考资料

  1. Java工具库Guava的区间(范围Range)的构建、区间运算、查询运算、关系运算(包含、相连、交集、并集)的使用示例 - 霸道流氓 - 博客园

你可能感兴趣的:(常用工具与脚本,guava,java)