相关文章推荐
幸福的墨镜  ·  django admin 时间线 - ...·  7 月前    · 
另类的酱肘子  ·  FileNotFoundException ...·  1 年前    · 
非常酷的双杠  ·  Mongo解决账户操作原子性问题_mongo ...·  1 年前    · 
豪气的电影票  ·  如何向json 文件中追加内容 - ...·  2 年前    · 
想表白的水桶  ·  关键字查询语言 (KQL) 语法参考 | ...·  2 年前    · 
Code  ›  Java 范围比较的推荐姿势开发者社区
assert localtime
https://cloud.tencent.com/developer/article/1901348
瘦瘦的菠萝
2 年前
作者头像
明明如月学长
0 篇文章

Java 范围比较的推荐姿势

前往专栏
腾讯云
开发者社区
文档 意见反馈 控制台
首页
学习
活动
专区
工具
TVP
文章/答案/技术大牛
发布
首页
学习
活动
专区
工具
TVP
返回腾讯云官网
社区首页 > 专栏 > 明明如月的技术专栏 > Java 范围比较的推荐姿势

Java 范围比较的推荐姿势

作者头像
明明如月学长
发布 于 2021-11-15 16:08:42
952 0
发布 于 2021-11-15 16:08:42
举报

一、背景

在平时工作开发过程中,很容易遇到判断某个值是否在某个范围的场景。

如需要校验某个日期是否在某个范围;需要校验某个版本号是否在某个区间;需要校验某个时间点是否在某个时间段内;判断某个人是否属于某个年龄段;判断某个用户的积分是否属于某个等级的区间等。

前一阵子,技术群里有哥们就提了类似的一个问题:

判断当前时间是否在周期的时间段里面有什么好的办法吗 比如 当前时间是2021-10-1 5:00:00 ,设置的时间段为 2021-9-30 1:00:00 -2021-9-30 18:00:00 周期为1天 。 那么每天的5-18点都在周期的时间段里面。 [合十]

有图有真相

在这里插入图片描述
在这里插入图片描述

群里也有不少同学表达自己的建议

在这里插入图片描述
在这里插入图片描述

还有

在这里插入图片描述
在这里插入图片描述

那么, 有没有比较优雅的判断方式呢?

二、建议

如果大家花点心思就可以对这些问题进行抽象,即所谓的范围就是数学里面的区间概念,是否在某个范围,即是否在该区间。

在这里插入图片描述
在这里插入图片描述

因此,我们可以定义一个区间,然后封装一个函数,传入某个值(区间上的某个点),返回是否在这个区间范围。

Guava 中提供了 com.google.common.collect.Range 类,就是为了解决这个问题。

同时还提供了一系列相关类如 RangeSet 、 ImmutableRangeSet ,可以帮助我们轻松实现区间合并,区间判断是否有重叠,实现区间的不可变特性等,非常强大,超级推荐。

maven 地址 https://mvnrepository.com/artifact/com.google.guava/guava

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

gradle 依赖

dependencies {
  // Pick one:
  // 1. Use Guava in your implementation only:
  implementation("com.google.guava:guava:31.0.1-jre")
  // 2. Use Guava types in your public API:
  api("com.google.guava:guava:31.0.1-jre")
  // 3. Android - Use Guava in your implementation only:
  implementation("com.google.guava:guava:31.0.1-android")
  // 4. Android - Use Guava types in your public API:
  api("com.google.guava:guava:31.0.1-android")
}

使用非常容易,只要需要比较的类型实现了 Comparable 接口,就直接可构造区间,然后拿值判断是否在这个区间中。

源码地址: https://github.com/google/guava

使用范例:

 public void test_Closed(){
    // 1点20分
    LocalTime start = LocalTime.of(1,20);
    // 8点12分
    LocalTime end = LocalTime.of(8,12);
    // 构造闭区间
    Range<LocalTime> localTimeRange = Range.closed(start,end);
    // 测试
    LocalTime time1 = LocalTime.of(6,4);
    Assert.assertTrue(localTimeRange.contains(time1));
    LocalTime time2 = LocalTime.of(1,20);
    Assert.assertTrue(localTimeRange.contains(time2));
    LocalTime time3 = LocalTime.of(1,19);
    Assert.assertFalse(localTimeRange.contains(time3));
    LocalTime time4 = LocalTime.of(9,19);
    Assert.assertFalse(localTimeRange.contains(time4));
  }

Range 官方的单元测试代码 https://github.com/google/guava/blob/master/guava-tests/test/com/google/common/collect/RangeTest.java

tabnine Range 代码使用范例

https://www.tabnine.com/code/java/classes/com.google.common.collect.Range

在这里插入图片描述
在这里插入图片描述

Range 还提供了很多方便的函数,还可以对多区间对象进行区交集( com.google.common.collect.Range#isConnected )、并集( com.google.common.collect.Range#intersection )等。

此外对于多段区间操作还提供了 com.google.common.collect.RangeSet 类。通过一个类构造出多个区间,然后传入一个值判断是否命中任意一个区间( com.google.common.collect.RangeSet#contains ),是否和另外一个区间有交集( com.google.common.collect.RangeSet#intersects )等,非常方便。

写一个简单的单测:

  public  void testLocalTIme(){
    List<Range<LocalTime>> ranges = new ArrayList<>();
    ranges.add(Range.closed(LocalTime.of(1,5),LocalTime.of(1,15)));
    ranges.add(Range.closed(LocalTime.of(8,25),LocalTime.of(9,15)));
    ranges.add(Range.closed(LocalTime.of(8,55),LocalTime.of(9,35)));
    RangeSet<LocalTime> rangeSet = ImmutableRangeSet.unionOf(ranges);
    Assert.assertTrue(rangeSet.contains(LocalTime.of(1,8)));
    Assert.assertFalse(rangeSet.contains(LocalTime.of(1,3)));
    Assert.assertTrue(rangeSet.contains(LocalTime.of(8,58)));
  }

详细使用方式,参考: https://www.tabnine.com/code/java/classes/com.google.common.collect.RangeSet

在这里插入图片描述
在这里插入图片描述

还有很多子类型 如 ImmutableRangeSet ,不可变的 RangeSet 帮助我们编码。

单测代码 https://github.com/google/guava/blob/master/guava-tests/test/com/google/common/collect/ImmutableRangeSetTest.java

com.google.common.collect.ImmutableRangeSetTest#testSingleBoundedRange

  public void testSingleBoundedRange() {
    ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.of(Range.closedOpen(1, 5));
    assertThat(rangeSet.asRanges()).contains(Range.closedOpen(1, 5));
    assertTrue(rangeSet.intersects(Range.closed(3, 4)));
    assertTrue(rangeSet.intersects(Range.closedOpen(0, 2)));
    assertTrue(rangeSet.intersects(Range.closedOpen(3, 7)));
    assertTrue(rangeSet.intersects(Range.greaterThan(2)));
    assertFalse(rangeSet.intersects(Range.greaterThan(7)));
    assertTrue(rangeSet.encloses(Range.closed(3, 4)));
    assertTrue(rangeSet.encloses(Range.closedOpen(1, 4)));
    assertTrue(rangeSet.encloses(Range.closedOpen(1, 5)));
    assertFalse(rangeSet.encloses(Range.greaterThan(2)));
    assertTrue(rangeSet.contains(3));
    assertFalse(rangeSet.contains(5));
    assertFalse(rangeSet.contains(0));
 
推荐文章
幸福的墨镜  ·  django admin 时间线 - hyu9999 - 博客园
7 月前
另类的酱肘子  ·  FileNotFoundException xxxxxxxxxx open failed: EPERM (Operation not permitted)-CSDN博客
1 年前
非常酷的双杠  ·  Mongo解决账户操作原子性问题_mongo incr-CSDN博客
1 年前
豪气的电影票  ·  如何向json 文件中追加内容 - cold_moon - 博客园
2 年前
想表白的水桶  ·  关键字查询语言 (KQL) 语法参考 | Microsoft Learn
2 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号