Guava 的 Ranges.asSet 输出无限列表

发布于 2024-11-15 09:36:37 字数 1545 浏览 4 评论 0原文

我正在尝试使用 Guava 的新 范围 功能,通过

Range<Date> dateRange = Ranges.range(start, BoundType.CLOSED, end, BoundType.CLOSED);

我的目标是获取此日期范围内的小时数。所以我创建了一个像这样的 DiscreteDomain:

private static final DiscreteDomain<Date> HOURS = new DiscreteDomain<Date>() {

    public Date next(Date value) {
        return addHours(value, 1);
    }

    private Date addHours(Date value, int i) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(value);
        cal.add(Calendar.HOUR_OF_DAY, i);
        return cal.getTime();
    }

    public Date previous(Date value) {
        return addHours(value, -1);
    }

    public long distance(Date start, Date end) {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(start);

        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(end);

        return cal2.getTimeInMillis() - cal1.getTimeInMillis();
    }

    public Date minValue() {
        return new Date(Long.MIN_VALUE);
    }

    public Date maxValue() {
        return new Date(Long.MAX_VALUE);
    }
};

如果我只是输出输出,我会得到

[Thu Feb 24 00:00:00 EST 2011..Thu Feb 24 00:02:00 EST 2011]

我真的想在范围内每个小时看到的闭集,但是,所以我尝试一个 for 循环:

for (Date hour : hours) {
    System.out.println(hour);
}

运行这个块时,我似乎得到一个无限的集合,从范围的左侧开始,但不在右侧停止,这让我杀死了 IDE。我做错了什么?

I am trying to get a date range using Guava's new Range functionality, via

Range<Date> dateRange = Ranges.range(start, BoundType.CLOSED, end, BoundType.CLOSED);

My goal is to get the hours in this date range. So I have created a DiscreteDomain like such:

private static final DiscreteDomain<Date> HOURS = new DiscreteDomain<Date>() {

    public Date next(Date value) {
        return addHours(value, 1);
    }

    private Date addHours(Date value, int i) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(value);
        cal.add(Calendar.HOUR_OF_DAY, i);
        return cal.getTime();
    }

    public Date previous(Date value) {
        return addHours(value, -1);
    }

    public long distance(Date start, Date end) {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(start);

        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(end);

        return cal2.getTimeInMillis() - cal1.getTimeInMillis();
    }

    public Date minValue() {
        return new Date(Long.MIN_VALUE);
    }

    public Date maxValue() {
        return new Date(Long.MAX_VALUE);
    }
};

If I merely sysout the output, I get the closed set

[Thu Feb 24 00:00:00 EST 2011..Thu Feb 24 00:02:00 EST 2011]

I really want to see each hour in the range, however, so I try a for loop:

for (Date hour : hours) {
    System.out.println(hour);
}

When running this block, I seem to get an infinite set, beginning at the left side of the range, but not stopping at the right side, making me kill the IDE. What am I doing wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

清风挽心 2024-11-22 09:36:37

我认为这可能是由于 ContigouslySet 返回的 Iterator 的行为(由 Range.asSet() 返回)造成的:

  @Override public UnmodifiableIterator<C> iterator() {
    return new AbstractLinkedIterator<C>(first()) {
      final C last = last();

      @Override
      protected C computeNext(C previous) {
        return equalsOrThrow(previous, last) ? null : domain.next(previous);
      }
    };
  }

  private static boolean equalsOrThrow(Comparable<?> left,
      @Nullable Comparable<?> right) {
    return right != null && compareOrThrow(left, right) == 0;
  }

  private static int compareOrThrow(Comparable left, Comparable right) {
    return left.compareTo(right);
  }

它只停止当下一个计算值等于范围的右边界时。

就您而言,您是否尝试过使用 Thu Feb 24 02:00:00 而不是 Thu Feb 24 00:02:00 作为范围的右边界来调用它?

我认为这种行为是有问题的,可能值得询问是否可以更改 equalsOrThrow() 来检查 left <= right 而不是 left == right


另外,您的 distance() 方法不正确。根据方法契约,它应该以小时为单位返回距离,而不是以毫秒为单位。


编辑 话

虽这么说,我相信真正的问题是,根据DiscreteDomain 的 javadoc:

离散域总是代表
其类型的整个值集;
它不能代表部分域
例如“素数”或“字符串
长度为 5。”

在您的例子中,您试图在每小时日期上创建一个离散域,这是所有日期的部分域。我认为,这是问题的根本原因。当您有部分域时,equalsOrThrow 方法变得不可靠,并且它可能“错过”范围的右边界。

I think this might be due to the behavior of the Iterator returned by the ContiguousSet (returned by Range.asSet()):

  @Override public UnmodifiableIterator<C> iterator() {
    return new AbstractLinkedIterator<C>(first()) {
      final C last = last();

      @Override
      protected C computeNext(C previous) {
        return equalsOrThrow(previous, last) ? null : domain.next(previous);
      }
    };
  }

  private static boolean equalsOrThrow(Comparable<?> left,
      @Nullable Comparable<?> right) {
    return right != null && compareOrThrow(left, right) == 0;
  }

  private static int compareOrThrow(Comparable left, Comparable right) {
    return left.compareTo(right);
  }

It only stops when the next computed value is equal to the right bound of the range.

In your case, have you tried calling it using Thu Feb 24 02:00:00 instead of Thu Feb 24 00:02:00 for the right bound of your range?

I think this behavior is problematic, and it might be worth asking if equalsOrThrow() could be changed to check for left <= right instead of left == right


Also, your distance() method is incorrect. It should return the distance in hours, not in milliseconds, according to the method contract.


EDIT

All this being said, I believe the real problem is that, according to the DiscreteDomain's javadoc:

A discrete domain always represents
the entire set of values of its type;
it cannot represent partial domains
such as "prime integers" or "strings
of length 5."

In your case, you are attempting to create a discrete domain over hourly dates, which is a partial domain of all dates. This is, I think, the root cause of the problem. When you have a partial domain, the equalsOrThrow method becomes unreliable, and it can "miss" the right bound of your range.

梦初启 2024-11-22 09:36:37

我刚刚尝试过这个,它对我来说效果很好。 @eneveu 也已经指出了您的 distance 方法的问题。我还猜测 startend 之间存在毫秒级的细微差别,这意味着您永远不会真正获得 Date通过在 start 上添加小时数等于 end

然而,这只是以不符合其设计目的的方式使用这些类的症状。 DiscreteDomain 的 Javadoc 指出:

离散域总是代表其类型的整个集合;它不能表示部分域,例如“素数”或“长度为 5 的字符串”。

“小时”的 DiscreteDomain 并不代表所有可能的 Date 对象的域,因此破坏了它的契约。

I just tried this and it worked fine for me. @eneveu already pointed out the issue with your distance method as well. I'm also guessing that there's some minor difference at the millisecond level between start and end which means that you'll never actually get a Date equal to end by adding hours to start.

However, that's all just symptoms of using the classes in a way they aren't designed to work. The Javadoc for DiscreteDomain states:

A discrete domain always represents the entire set of values of its type; it cannot represent partial domains such as "prime integers" or "strings of length 5."

A DiscreteDomain of "hours" does not represent the domain of all possible Date objects and as such breaks its contract.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文