原文链接 译文链接 译文:沈义扬

范例

1    List scores;
2 Iterable belowMedian =Iterables.filter(scores,Range.lessThan(median));
3 ...
4 Range validGrades = Range.closed(1, 12);
5 for(int grade : ContiguousSet.create(validGrades, DiscreteDomain.integers())) {
6 ...
7 }

简介

区间,有时也称为范围,是特定域中的凸性(非正式说法为连续的或不中断的)部分。在形式上,凸性表示对a<=b<=c, range.contains(a)且range.contains(c)意味着range.contains(b)。

区间可以延伸至无限——例如,范围”x>3″包括任意大于3的值——也可以被限制为有限,如” 2<=x<5″。Guava用更紧凑的方法表示范围,有数学背景的程序员对此是耳熟能详的:

  • (a..b) = {x | a < x < b}
  • [a..b] = {x | a <= x <= b}
  • [a..b) = {x | a <= x < b}
  • (a..b] = {x | a < x <= b}
  • (a..+∞) = {x | x > a}
  • [a..+∞) = {x | x >= a}
  • (-∞..b) = {x | x < b}
  • (-∞..b] = {x | x <= b}
  • (-∞..+∞) = 所有值

上面的a、b称为端点 。为了提高一致性,Guava中的Range要求上端点不能小于下端点。上下端点有可能是相等的,但要求区间是闭区间或半开半闭区间(至少有一个端点是包含在区间中的):

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

Guava用类型Range<C>表示区间。所有区间实现都是不可变类型。

构建区间

区间实例可以由Range类的静态方法获取:

(a..b) open(C, C)
[a..b] closed(C, C)
[a..b) closedOpen(C, C)
(a..b] openClosed(C, C)
(a..+∞) greaterThan(C)
[a..+∞) atLeast(C)
(-∞..b) lessThan(C)
(-∞..b] atMost(C)
(-∞..+∞) all()
1 Range.closed("left""right"); //字典序在"left"和"right"之间的字符串,闭区间
2 Range.lessThan(4.0); //严格小于4.0的double值

此外,也可以明确地指定边界类型来构造区间:

有界区间 range(C, BoundType, C,   BoundType)
无上界区间:((a..+∞) 或[a..+∞)) downTo(C, BoundType)
无下界区间:((-∞..b) 或(-∞..b]) upTo(C, BoundType)

这里的BoundType是一个枚举类型,包含CLOSED和OPEN两个值。

1    Range.downTo(4, boundType);// (a..+∞)或[a..+∞),取决于boundType
2 Range.range(1, CLOSED, 4, OPEN);// [1..4),等同于Range.closedOpen(1, 4)

区间运算

Range的基本运算是它的contains(C) 方法,和你期望的一样,它用来区间判断是否包含某个值。此外,Range实例也可以当作Predicate,并且在函数式编程中使用(译者注:见第4章)。任何Range实例也都支持containsAll(Iterable<? extends C>)方法:

1    Range.closed(1, 3).contains(2);//return true
2 Range.closed(1, 3).contains(4);//return false
3 Range.lessThan(5).contains(5); //return false
4 Range.closed(1, 4).containsAll(Ints.asList(1, 2, 3)); //return true

查询运算

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

1    Range.closedOpen(4, 4).isEmpty(); // returns true
2 Range.openClosed(4, 4).isEmpty(); // returns true
3 Range.closed(4, 4).isEmpty(); // returns false
4 Range.open(4, 4).isEmpty(); // Range.open throws IllegalArgumentException
5 Range.closed(3, 10).lowerEndpoint(); // returns 3
6 Range.open(3, 10).lowerEndpoint(); // returns 3
7 Range.closed(3, 10).lowerBoundType(); // returns CLOSED
8 Range.open(3, 10).upperBoundType(); // returns OPEN

关系运算

包含[enclose]

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

  • [3..6] 包含[4..5] ;
  • (3..6) 包含(3..6) ;
  • [3..6] 包含[4..4),虽然后者是空区间;
  • (3..6]不 包含[3..6] ;
  • [4..5]不 包含(3..6),虽然前者包含了后者的所有值,离散域[discrete domains]可以解决这个问题(见8.5节);
  • [3..6]不 包含(1..1],虽然前者包含了后者的所有值。

包含是一种偏序关系[partial ordering]。基于包含关系的概念,Range还提供了以下运算方法。

相连[isConnected]

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

相连是一种自反的[reflexive]、对称的[symmetric]关系。

1    Range.closed(3, 5).isConnected(Range.open(5, 10)); // returns true
2 Range.closed(0, 9).isConnected(Range.closed(3, 4)); // returns true
3 Range.closed(0, 5).isConnected(Range.closed(3, 9)); // returns true
4 Range.open(3, 5).isConnected(Range.open(5, 10)); // returns false
5 Range.closed(1, 5).isConnected(Range.closed(6, 10)); // returns false

交集[intersection]

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

交集是可互换的[commutative] 、关联的[associative] 运算[operation]。

1    Range.closed(3, 5).intersection(Range.open(5, 10)); // returns (5, 5]
2 Range.closed(0, 9).intersection(Range.closed(3, 4)); // returns [3, 4]
3 Range.closed(0, 5).intersection(Range.closed(3, 9)); // returns [3, 5]
4 Range.open(3, 5).intersection(Range.open(5, 10)); // throws IAE
5 Range.closed(1, 5).intersection(Range.closed(6, 10)); // throws IAE

跨区间[span]

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

span是可互换的[commutative] 、关联的[associative] 、闭合的[closed]运算[operation]。

1    Range.closed(3, 5).span(Range.open(5, 10)); // returns [3, 10)
2 Range.closed(0, 9).span(Range.closed(3, 4)); // returns [0, 9]
3 Range.closed(0, 5).span(Range.closed(3, 9)); // returns [0, 9]
4 Range.open(3, 5).span(Range.open(5, 10)); // returns (3, 10)
5 Range.closed(1, 5).span(Range.closed(6, 10)); // returns [1, 10]

离散域

部分(但不是全部)可比较类型是离散的,即区间的上下边界都是可枚举的。

在Guava中,用DiscreteDomain<C>实现类型C的离散形式操作。一个离散域总是代表某种类型值的全集;它不能代表类似”素数”、”长度为5的字符串”或”午夜的时间戳”这样的局部域。

DiscreteDomain提供的离散域实例包括:

类型 离散域
Integer integers()
Long longs()

一旦获取了DiscreteDomain实例,你就可以使用下面的Range运算方法:

  • ContiguousSet.create(range, domain):用ImmutableSortedSet<C>形式表示Range<C>中符合离散域定义的元素,并增加一些额外操作——译者注:实际返回ImmutableSortedSet的子类ContiguousSet。(对无限区间不起作用,除非类型C本身是有限的,比如int就是可枚举的)
  • canonical(domain):把离散域转为区间的”规范形式”。如果ContiguousSet.create(a, domain).equals(ContiguousSet.create(b, domain))并且!a.isEmpty(),则有a.canonical(domain).equals(b.canonical(domain))。(这并不意味着a.equals(b))
1    ImmutableSortedSet set = ContigousSet.create(Range.open(1, 5), iscreteDomain.integers());
2 //set包含[2, 3, 4]
3 ContiguousSet.create(Range.greaterThan(0), DiscreteDomain.integers());
4 //set包含[1, 2, ..., Integer.MAX_VALUE]

注意,ContiguousSet.create并没有真的构造了整个集合,而是返回了set形式的区间视图。

你自己的离散域

你可以创建自己的离散域,但必须记住DiscreteDomain契约的几个重要方面。

  • 一个离散域总是代表某种类型值的全集;它不能代表类似”素数”或”长度为5的字符串”这样的局部域。所以举例来说,你无法构造一个DiscreteDomain以表示精确到秒的JODA DateTime日期集合:因为那将无法包含JODA DateTime的所有值。
  • DiscreteDomain可能是无限的——比如BigInteger DiscreteDomain。这种情况下,你应当用minValue()和maxValue()的默认实现,它们会抛出NoSuchElementException。但Guava禁止把无限区间传入ContiguousSet.create——译者注:那明显得不到一个可枚举的集合。

如果我需要一个Comparator呢?

我们想要在Range的可用性与API复杂性之间找到特定的平衡,这部分导致了我们没有提供基于Comparator的接口:我们不需要操心区间是怎样基于不同Comparator互动的;所有API签名都是简单明确的;这样更好。

另一方面,如果你需要任意Comparator,可以按下列其中一项来做:

  • 使用通用的Predicate接口,而不是Range类。(Range实现了Predicate接口,因此可以用Predicates.compose(range, function)获取Predicate实例)
  • 使用包装类以定义期望的排序。

译者注:实际上Range规定元素类型必须是Comparable,这已经满足了大多数需求。如果需要自定义特殊的比较逻辑,可以用Predicates.compose(range, function)组合比较的function。

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: [Google Guava] 8-区间

[Google Guava] 8-区间的更多相关文章

  1. Google Guava官方教程(中文版)

    Google Guava官方教程(中文版) 原文链接  译文链接 译者: 沈义扬,罗立树,何一昕,武祖  校对:方腾飞 引言 Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库, ...

  2. 初探Google Guava

    Guava地址:https://github.com/google/guava 第一次接触我是在16年春github上,当时在找单机查缓存方法,google guava当初取名是因为JAVA的类库不好 ...

  3. Google Guava新手教程

         以下资料整理自网络 一.Google Guava入门介绍 引言 Guavaproject包括了若干被Google的 Java项目广泛依赖 的核心库,比如:集合 [collections] . ...

  4. [Google Guava] 4-函数式编程

    原文链接 译文链接 译者:沈义扬,校对:丁一 注意事项 截至JDK7,Java中也只能通过笨拙冗长的匿名类来达到近似函数式编程的效果.预计JDK8中会有所改变,但Guava现在就想给JDK5以上用户提 ...

  5. Google Guava入门教程

    以下资料整理自网络 一.Google Guava入门介绍 引言 Guava 工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] .缓存 [cachi ...

  6. java开发人员,最应该学习和熟练使用的工具类。google guava.(谷歌 瓜娃)

    学习参考文章: http://blog.csdn.net/wisgood/article/details/13297535 http://ifeve.com/google-guava/ http:// ...

  7. [转]Google Guava官方教程(中文版)

    Google Guava官方教程(中文版) http://ifeve.com/google-guava/

  8. Google Guava vs Apache Commons for Argument Validation

    It is an established good practice to validate method arguments at the beginning of the method body. ...

  9. 使用 Google Guava 美化你的 Java 代码

    文章转载自:http://my.oschina.net/leejun2005/blog/172328 目录:[ - ] 1-使用 GOOGLE COLLECTIONS,GUAVA,STATIC IMP ...

随机推荐

  1. ORA-01078: failure in processing system parameters LRM-00109: could not open parameter file '/u01/app/oracle/product/19.2.0/db_1/dbs/initsanshi.ora'报错

    本人是在Linux安装Oracle19C之后,启动数据库时,XSHELL命令行窗口报的该错误,看了几个解决方案之后,总结如下 从字面的意思来看,是在dbs目录当中没有这个initsanshi.ora文 ...

  2. LC 173. Binary Search Tree Iterator

    题目描述 Implement an iterator over a binary search tree (BST). Your iterator will be initialized with t ...

  3. python中检测某个变量是否有定义

    目录 第一种方法使用内置函数locals() 第二种方法使用内置函数dir() 第三种方法使用内置函数vars() 第一种方法使用内置函数locals() 'testvar' in locals(). ...

  4. tuxedo10g3R的安装过程(原文url:http://www.cnblogs.com/xianfish/articles/1955244.html)

      RHEL 5.1 32Bit 安装配置TUXEDO 10R3 [前言]: 目的: 在Linux上安装配置Tuxedo 10R3 环境: RHEL 5.1 32Bit [前提条件]: 下载Tuxed ...

  5. Bloom过滤器

    提出一个问题 在我们细述Bloom过滤器之前,我们先抛出一个问题:给你一个巨大的数据集(百万级.亿级......),怎么判断一个元素是否在此数据集中?或者怎么判断一个元素不在此数据集中? 思考这个问题 ...

  6. IDEA中通过Maven插件使用MyBatis Generator

    这样做更简单,参考: IDEA集成MyBatis Generator 插件 详解

  7. (八)装配Bean(2)

    二.在Java类中进行显式的装配 显式配置有两种: 1. 一种是在java(本文讲解)   2. 另一种是xml配置文件(第一章有讲) 案例一: 使用java显式装配+@autowired自动装配的方 ...

  8. (八)Struts标签基础(一)

    一.Struts标签分类 二.标签的使用 2.1 标签的主题 主题的设置与struts.xml中的常量<constant name="struts.ui.theme" val ...

  9. c#基础知识梳理(三)

    上期回顾 - https://www.cnblogs.com/liu-jinxin/p/10824638.html 一.方法 一个方法是把一些相关的语句组织在一起,用来执行一个任务的语句块.每一个 C ...

  10. 【轻松一刻】Java制作字符动画

    前言 今晚闲来无事,整理了一下电脑中尘封已久的旧代码,看着那些年自己写过的代码,踩过的坑,顿时老泪纵横.正当在感叹之际,突然发现在“马克思”文件夹下出现了一个好玩的项目,那就是N年前刚学Java时写的 ...