Java 调节器与查询,给定一个时态值(temporal value),用户希望根据自定义逻辑对其进行调整,或检索给定值的相关信息,可以创建 TemporalAdjuster
或规划 TemporalQuery
接口。TemporalAdjuster
和 TemporalQuery
接口中的类不仅提供使用 Date-Time API 中各种类的有趣方式,也提供有用的内置方法以实现用户自定义的方法。
Java 调节器与查询 问题描述
给定一个时态值(temporal value),用户希望根据自定义逻辑对其进行调整,或检索给定值的相关信息。
Java 调节器与查询 解决方案
创建 TemporalAdjuster
或规划 TemporalQuery
接口。
Java 调节器与查询 具体实例
TemporalAdjuster
和 TemporalQuery
接口中的类不仅提供使用 Date-Time API 中各种类的有趣方式,也提供有用的内置方法以实现用户自定义的方法。本范例将对此做讨论。
1.TemporalAdjuster
的应用
TemporalAdjuster
接口定义了一个名为 adjustInto
的方法,它传入 Temporal
值作为参数,并返回调整后的值。而 TemporalAdjusters
类包括一系列用作静态方法的调节器(adjuster),或许能为开发带来一定便利。
以 LocalDateTime
类为例,我们可以通过时态对象(temporal object)上的 with
方法使用 TemporalAdjuster
:
虽然也可以使用 TemporalAdjuster
接口定义的 adjustInto
方法,但 with
方法应作为首选。
我们首先讨论 TemporalAdjusters
类,它定义了多种便利的方法:
例 8-10 的用例显示了上述方法在实际开发中的应用。
例 8-10
TemporalAdjusters
类定义的部分静态方法
有趣之处在于编写自定义调节器。TemporalAdjuster
是一个函数式接口,所包含的单一抽象方法为:
在讨论时态调节器(temporal adjuster)时,Java 官方教程以 PaydayAdjuster
类为例演示了自定义调节器的应用:假设员工在一个月中领取两次工资,且发薪日是每月 15 日和最后一天;如果某个发薪日为周末,则提前到周五。
为便于参考,例 8-11 完整复制了这个示例的代码。请注意,adjustInto
方法已被添加到实现 TemporalAdjuster
接口的 PaydayAdjuster
类中。
例 8-11
PaydayAdjuster
类(取自 Java 官方教程)
➊ from
方法可以将任何时态对象转换为 LocalDate
以 2017 年 7 月为例运行程序,其中 7 月 15 日是周六,7 月 31 日是周一。例 8-12 的测试显示,调节器可以正确处理 2017 年 7 月的发薪日。
例 8-12 测试调节器
虽然上述程序可以运行,但仍然存在改进的空间。首先,在 Java 8 之前,如果不使用其他机制就无法创建日期流(例如,本例需要计算天数)。这种情况在 Java 9 中得以改变。Java 9 新增了一种返回日期流的方法 datesUntil
,详细讨论请参见范例日期范围。
其次,为实现 TemporalAdjuster
接口,程序创建了 PaydayAdjuster
类。由于 TemporalAdjuster
属于函数式接口,不妨改为提供 lambda 表达式或方法引用作为实现。
如例 8-13 所示,我们创建一个名为 Adjusters
的工具类,它包括进行各种操作所需的静态方法。
例 8-13 工具类 Adjusters
❶ 不实现 TemporalAdjuster
接口
❷ 静态方法无须实例化
重写后的测试如例 8-14 所示。
例 8-14 测试调节器(使用方法引用)
➊ adjustInto
的方法引用
如果存在多个时态调节器,上述方案可能更为通用。
2.TemporalQuery
的应用
TemporalQuery
接口用作时态对象中 query
方法的参数。以 LocalDate
类为例,query
方法的签名如下:
query
方法调用 TemporalQuery.queryFrom(TemporalAccessor)
方法(传入 this
作为参数),并返回所需的查询。TemporalAccessor
接口定义的所有方法均可用于查询操作。
Date-Time API 还包括一个名为 TemporalQueries
的类,它定义了许多常见查询的常量:
例 8-15 的简单测试展示了部分方法的应用。
例 8-15
TemporalQueries
类定义的部分方法
与 TemporalAdjuster
接口类似,有趣之处在于编写自定义查询。TemporalQuery
接口包含的单一抽象方法为:
如果给定参数 TemporalAccessor
,我们可以编写一个名为 daysUntilPirateDay
的方法,以计算指定日期与国际海盗模仿日(International Talk Like A Pirate Day,9 月 19 日)5 之间的天数,如例 8-16 所示。
例 8-16 计算指定日期与国际海盗模仿日之间的天数
由于 daysUntilPirateDay
方法的签名与 TemporalQuery
接口包含的单一抽象方法 queryFrom
相互兼容,可以通过方法引用来调用,如例 8-17 所示。
例 8-17 通过方法引用使用
TemporalQuery
上述方案也可用于创建自定义查询。
5例如,“喂,伙计!我打算把你加入我的 LinkedIn 社交网络。”