Guava's Ranges.asSet выводит бесконечный список - PullRequest
3 голосов
/ 14 июня 2011

Я пытаюсь получить диапазон дат, используя новые функции Диапазон в 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.Что я делаю не так?

Ответы [ 2 ]

6 голосов
/ 14 июня 2011

Я думаю, это может быть связано с поведением Iterator, возвращаемым ContiguousSet (возвращаемым 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() метод неверен. Он должен возвращать расстояние в часах, а не в миллисекундах, в соответствии с контрактом метода.


EDIT

При всем этом, я считаю, что реальная проблема заключается в том, что, согласно DiscreteDomain's javadoc:

Дискретный домен всегда представляет весь набор значений своего типа; он не может представлять частичные домены такие как "простые целые числа" или "строки длиной 5 ".

В вашем случае вы пытаетесь создать отдельный домен за почасовых дат , который является частичным доменом всех дат. Это, я думаю, коренная причина проблемы. Когда у вас есть частичный домен, метод equalsOrThrow становится ненадежным, и он может «пропустить» правую границу вашего диапазона.

3 голосов
/ 14 июня 2011

Я только что попробовал это, и это работало хорошо для меня. @eneveu уже указал на проблему с вашим методом distance. Я также предполагаю, что есть некоторая небольшая разница на уровне миллисекунд между start и end, что означает, что вы никогда не получите Date, равный end, добавив часы к start.

Однако это всего лишь симптомы использования классов таким образом, что они не предназначены для работы. В Javadoc для DiscreteDomain говорится:

Дискретный домен всегда представляет полный набор значений его типа; он не может представлять частичные домены, такие как «простые целые числа» или «строки длиной 5».

DiscreteDomain «часов» не представляет домен всех возможных Date объектов и, как таковой, нарушает его контракт.

...