范例

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

简介

区间,有时也称为范围,是特定域中的凸性(非正式说法为连续的或不中断的)部分。在形式上,凸性表示对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()
Range.closed("left", "right"); //字典序在"left"和"right"之间的字符串,闭区间
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两个值。

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

区间运算

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

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

查询运算

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

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

关系运算

包含[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]关系。

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

交集[intersection]

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

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

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

跨区间[span]

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

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

Range.closed(3, 5).span(Range.open(5, 10)); // returns [3, 10)
Range.closed(0, 9).span(Range.closed(3, 4)); // returns [0, 9]
Range.closed(0, 5).span(Range.closed(3, 9)); // returns [0, 9]
Range.open(3, 5).span(Range.open(5, 10)); // returns (3, 10)
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))
ImmutableSortedSet set = ContigousSet.create(Range.open(1, 5), iscreteDomain.integers());
//set包含[2, 3, 4]
ContiguousSet.create(Range.greaterThan(0), DiscreteDomain.integers());
//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。

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

  1. guava(四)区间Ranges

    一.构建区间 (a..b) open(C, C) [a..b] closed(C, C) [a..b) closedOpen(C, C) (a..b] openClosed(C, C) (a..+∞) ...

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

      原文链接  译文链接 译者: 沈义扬,罗立树,何一昕,武祖  校对:方腾飞 引言 Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] ...

  3. Guava学习-目录

    备份一下地址: 目录 1. 基本工具 [Basic utilities] 让使用Java语言变得更舒适 1.1 使用和避免null:null是模棱两可的,会引起令人困惑的错误,有些时候它让人很不舒服. ...

  4. Guava学习笔记(2):Preconditions优雅的检验参数

    转自:http://www.cnblogs.com/peida/p/Guava_Preconditions.html 在日常开发中,我们经常会对方法的输入参数做一些数据格式上的验证,以便保证方法能够按 ...

  5. guava学习--Preconditions

    转载:https://my.oschina.net/realfighter/blog/349819 Preconditions是guava提供的用于进行代码校验的工具类,其中提供了许多重要的静态校验方 ...

  6. Guava学习笔记:Range

    在Guava中新增了一个新的类型Range,从名字就可以了解到,这个是和区间有关的数据结构.从Google官方文档可以得到定义:Range定义了连续跨度的范围边界,这个连续跨度是一个可以比较的类型(C ...

  7. Guava学习笔记:Preconditions优雅的检验参数

    在日常开发中,我们经常会对方法的输入参数做一些数据格式上的验证,以便保证方法能够按照正常流程执行下去.对于可预知的一些数据上的错误,我们一定要做事前检测和判断,来避免程序流程出错,而不是完全通过错误处 ...

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

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

  9. guava函数式编程

    [Google Guava] 4-函数式编程 原文链接 译文链接 译者:沈义扬,校对:丁一 注意事项 截至JDK7,Java中也只能通过笨拙冗长的匿名类来达到近似函数式编程的效果.预计JDK8中会有所 ...

  10. guava学习--集合2&Range

    转载:http://www.cnblogs.com/peida/p/Guava_ImmutableCollections.html Table: 当我们需要多个索引的数据结构的时候,通常情况下,我们只 ...

随机推荐

  1. Hightchart.js 的使用

    中文网址介绍 http://www.hcharts.cn/docs/basic-zoom http://v1.hcharts.cn/demo/index.php?p=46

  2. 论文笔记之:Fully-Convolutional Siamese Networks for Object Tracking

    gansh Fully-Convolutional Siamese Network for Object Tracking 摘要:任意目标的跟踪问题通常是根据一个物体的外观来构建表观模型.虽然也取得了 ...

  3. pgbouncer配置

    DESCRIPTION pgbouncer is a PostgreSQL connection pooler. Any target application can be connected to  ...

  4. 在apache连接多php的时候遇到了问题,怎么切换多个php版本?

    PHP 在apache连接多php的时候遇到了问题,怎么切换多个php版本? 我的机器里面有一个apache2.2.22,但是有两个php,5.3.10和5.4.3,5.3.10是mac os x带的 ...

  5. java 中的断言assert的使用

    一.assertion的意义和用法 J2SE 1.4在语言上提供了一个新特性,就是assertion功能,它是该版本在Java语言方面最大的革新. 从理论上来说,通过 assertion方式可以证明程 ...

  6. 关于CSS Hack

    CSS Hack由于不同厂商的浏览器,如Internet Explorer,Safari,Mozilla Firefox,Chrome 等,或者是同一厂商的浏览器的不同版本,如IE6和IE7,对CSS ...

  7. .net 开源 JavaScript 解析引擎

    1. Javascript .NET 地址为:http://javascriptdotnet.codeplex.com/ 使用方法: Quick Start This section provides ...

  8. RSA非对称加密 php的openssl实现

    <?php /** * 使用openssl实现非对称加密 * @since 2010-07-08 */ class Rsa { /** * private key */ private $_pr ...

  9. SQL SERVER 复制相关存储过程

    适用于所有类型复制的过程 过程 说明 sp_addscriptexec 向发布的所有订阅服务器发布 Microsoft SQL Server 脚本(.sql 文件). sp_adjustpublish ...

  10. 关于Schema设计规范及SQL使用建议

    1.所有的InnoDB表都设计一个无业务用途的自增列做主键,对于绝大多数场景都是如此,真正纯只读用InnoDB表的并不多,真如此的话还不如用TokuDB来得划算: 2.字段长度满足需求前提下,尽可能选 ...