【问题标题】:Is there a way to express the "sign" of a TemporalAmount?有没有办法表达 TemporalAmount 的“标志”?
【发布时间】:2019-08-07 18:32:09
【问题描述】:

基于这个answer,我决定实现我自己的MutableClock 用于单元测试目的,其工作方式略有不同:

class MutableClock extends Clock {
  private final List<Instant> instants = new ArrayList<>();

  public MutableClock(Instant now, TemporalAmount... amounts) {
    Objects.requireNonNull(now, "now must not be null");
    Objects.requireNonNull(amounts, "amounts must not be null");
    instants.add(now);
    for (TemporalAmount amount : amounts) {
        Instant latest = instants.get(instants.size() - 1);
        instants.add(latest.plus(amount));
    }
  }

  @Override
  public Instant instant() {
    Instant latest = instants.get(0);
    if (instants.size() > 1) {
        instants.remove(0);
    }
    return latest;
  }

  ... 

但后来我注意到我在这里这样做:

instants.add(latest.plus(amount));

所以,基本上,我只能将时钟“向前”打勾。当然,这在大多数情况下是有道理的,但由于所有这些都是为了单元测试,我可以想象我想使用这样的 MutableClock 实例并让它返回并不总是“增加”的瞬间。

但是在查看TemporalAmount 界面时:没有办法表示否定时间量?!换句话说:TemporalAmount 的实例似乎没有“签名”。

那么,怎么办呢?

【问题讨论】:

  • 有否被否决者投票?
  • 没有办法表示负的时间量?!”诶?让get(TemporalUnit unit) 返回一个负值。

标签: java datetime java-time


【解决方案1】:

TemporalAmount 由 java.time 中的两个类实现:DurationPeriod。当然,用户也可以编写他或她自己的接口实现。我没有检查,但我会假设 ThreeTen Extra 项目的 PeriodDuration 类也实现了该接口。您可能认为您不能将Period 添加到Instant,因为Instant 不知道日期、月份和年份,而这正是Period 的组成部分。一般来说,你不能,但在某些情况下你可以。添加 Period.ZEROPeriod.ofWeeks(3) 效果很好(后者将一周定义为 168 小时,我们知道当夏令时开始和结束时,这是不正确的,但仍然可以这样做)。简而言之:我们不能安全地假设TemporalAmountDuration

如果你想对界面进行编程,一个相当简单的技巧是在添加数量时检查时钟是否真的倒退:

        Instant latest = instants.get(instants.size() - 1);
        Instant newInstant = latest.plus(amount);
        if (newInstant.isBefore(latest)) {
            // The amount was negative; do whatever handling of the situation you need
        } else {
            instants.add(newInstant);
        }

当然,如果你想让你的时钟倒退,不需要对这种情况进行特殊处理(你可以省略if-else 构造)。正如您在自己的回答中指出的那样,创建负数没有问题,例如 Duration.ofSeconds(-5)Period.ofWeeks(-3)

为什么界面不提供负数测试和/或求反方法?

虽然Duration 总是明确地是负数、零或正数,但对于Period 则不成立。 Period.ofMonths(1).minusDays(30) 可能是负数、零或正数,具体取决于月份的选择。奇怪的是 Period 有一个 isNegative 方法,但它只是测试三个单位(年、月、日)中的任何一个是否为负,因此语义不是您需要的.所以Period.ofMonths(1).minusDays(3).isNegative() 返回true

【讨论】:

  • 有趣的地方。也许真正的答案也是改变我的代码,不再使用那个接口,而是简单地依赖 Duration 本身。这清楚地表达了意图,也避免了人们在 Period 实例中推动然后发生奇怪的事情。
  • 听起来不错。 java.time 的接口并非全部供日常应用程序(或测试)程序员使用,因此,如果直接依赖 Duration 会使事情变得更简单或更容易,那么一定要这样做(我赶紧投票赞成你自己的答案)同一个方向)。
【解决方案2】:

这个问题可以直接解决:只需查看该接口的具体实现,即Duration。该类实际上提供了 negated() 来否定 Duration 实例。

因此,当传递负 Duration 时,上述实现已经有效:

@Test
public void testNegativeAdjustments() {
    Instant now = Instant.now();
    Duration amount = Duration.ofSeconds(5);
    TemporalAmount negativeAmount = amount.negated();
    MutableClock underTest = new MutableClock(now, negativeAmount);
    assertThat(underTest.instant(), is(now));
    assertThat(underTest.instant(), is(amount.subtractFrom(now)));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-06
    • 2019-11-07
    • 1970-01-01
    • 1970-01-01
    • 2013-10-12
    • 1970-01-01
    • 2013-02-26
    • 1970-01-01
    相关资源
    最近更新 更多