From 721fd16f4da4bd2de2300973987b83a61f8f44a6 Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 29 Jun 2021 21:15:19 +0800 Subject: [PATCH] fix Range --- .../java/cn/hutool/core/date/DateRange.java | 1 - .../main/java/cn/hutool/core/lang/Range.java | 70 ++++++++++--------- .../cn/hutool/core/date/DateUtilTest.java | 42 ----------- .../java/cn/hutool/core/lang/RangeTest.java | 52 ++++++++++++++ 4 files changed, 89 insertions(+), 76 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateRange.java b/hutool-core/src/main/java/cn/hutool/core/date/DateRange.java index 432bfa3d4..ca8aa084a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateRange.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateRange.java @@ -52,7 +52,6 @@ public class DateRange extends Range { if (dt.isAfter(end1)) { return null; } - return dt; }, isIncludeStart, isIncludeEnd); } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/Range.java b/hutool-core/src/main/java/cn/hutool/core/lang/Range.java index 4a7f1eb72..dbee96127 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/Range.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/Range.java @@ -11,7 +11,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; /** * 范围生成器。根据给定的初始值、结束值和步进生成一个步进列表生成器
- * 由于用户自行实现{@link Steper}来定义步进,因此Range本身无法判定边界(是否达到end),需在step实现边界判定逻辑。 + * 由于用户自行实现{@link Stepper}来定义步进,因此Range本身无法判定边界(是否达到end),需在step实现边界判定逻辑。 * *

* 此类使用{@link ReentrantReadWriteLock}保证线程安全 @@ -35,10 +35,6 @@ public class Range implements Iterable, Iterator, Serializable { * 结束对象 */ private final T end; - /** - * 当前对象 - */ - private T current; /** * 下一个对象 */ @@ -46,7 +42,7 @@ public class Range implements Iterable, Iterator, Serializable { /** * 步进 */ - private final Steper steper; + private final Stepper stepper; /** * 索引 */ @@ -58,27 +54,27 @@ public class Range implements Iterable, Iterator, Serializable { /** * 是否包含最后一个元素 */ - private boolean includeEnd; + private final boolean includeEnd; /** * 构造 * - * @param start 起始对象(包括) - * @param steper 步进 + * @param start 起始对象(包括) + * @param stepper 步进 */ - public Range(T start, Steper steper) { - this(start, null, steper); + public Range(T start, Stepper stepper) { + this(start, null, stepper); } /** * 构造 * - * @param start 起始对象(包含) - * @param end 结束对象(包含) - * @param steper 步进 + * @param start 起始对象(包含) + * @param end 结束对象(包含) + * @param stepper 步进 */ - public Range(T start, T end, Steper steper) { - this(start, end, steper, true, true); + public Range(T start, T end, Stepper stepper) { + this(start, end, stepper, true, true); } /** @@ -86,23 +82,22 @@ public class Range implements Iterable, Iterator, Serializable { * * @param start 起始对象 * @param end 结束对象 - * @param steper 步进 + * @param stepper 步进 * @param isIncludeStart 是否包含第一个元素 * @param isIncludeEnd 是否包含最后一个元素 */ - public Range(T start, T end, Steper steper, boolean isIncludeStart, boolean isIncludeEnd) { + public Range(T start, T end, Stepper stepper, boolean isIncludeStart, boolean isIncludeEnd) { + Assert.notNull(start, "First element must be not null!"); this.start = start; - this.current = start; this.end = end; - this.steper = steper; - this.next = safeStep(this.current); + this.stepper = stepper; + this.next = safeStep(this.start); this.includeStart = isIncludeStart; - includeEnd = true; this.includeEnd = isIncludeEnd; } /** - * 禁用锁,调用此方法后不在 使用锁保护 + * 禁用锁,调用此方法后不再使用锁保护 * * @return this * @since 4.3.1 @@ -147,30 +142,38 @@ public class Range implements Iterable, Iterator, Serializable { * 获取下一个元素,并将下下个元素准备好 */ private T nextUncheck() { - if (0 != this.index || false == this.includeStart) { - // 非第一个元素或不包含第一个元素增加步进 - this.current = this.next; - if (null != this.current) { - this.next = safeStep(this.next); + T current; + if(0 == this.index){ + current = start; + if(false == this.includeStart){ + // 获取下一组元素 + index ++; + return nextUncheck(); } + } else { + current = next; + this.next = safeStep(this.next); } + index++; - return this.current; + return current; } /** * 不抛异常的获取下一步进的元素,如果获取失败返回{@code null} * - * @param base 上一个元素 + * @param base 上一个元素 * @return 下一步进 */ private T safeStep(T base) { + final int index = this.index; T next = null; try { - next = steper.step(base, this.end, this.index); + next = stepper.step(base, this.end, index); } catch (Exception e) { // ignore } + return next; } @@ -192,8 +195,8 @@ public class Range implements Iterable, Iterator, Serializable { public Range reset() { lock.lock(); try { - this.current = this.start; this.index = 0; + this.next = safeStep(this.start); } finally { lock.unlock(); } @@ -213,7 +216,8 @@ public class Range implements Iterable, Iterator, Serializable { * @param 需要增加步进的对象 * @author Looly */ - public interface Steper { + @FunctionalInterface + public interface Stepper { /** * 增加步进
* 增加步进后的返回值如果为{@code null}则表示步进结束
diff --git a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java index 1fdccbb56..157049b8f 100644 --- a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java @@ -19,7 +19,6 @@ import java.util.Date; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; -import java.util.NoSuchElementException; import java.util.Objects; import java.util.TimeZone; @@ -681,47 +680,6 @@ public class DateUtilTest { Assert.assertEquals(Week.WEDNESDAY, week); } - @Test - public void rangeTest() { - DateTime start = DateUtil.parse("2017-01-01"); - DateTime end = DateUtil.parse("2017-01-03"); - - // 测试包含开始和结束情况下步进为1的情况 - DateRange range = DateUtil.range(start, end, DateField.DAY_OF_YEAR); - Assert.assertEquals(range.next(), DateUtil.parse("2017-01-01")); - Assert.assertEquals(range.next(), DateUtil.parse("2017-01-02")); - Assert.assertEquals(range.next(), DateUtil.parse("2017-01-03")); - try { - range.next(); - Assert.fail("已超过边界,下一个元素不应该存在!"); - } catch (NoSuchElementException ignored) { - } - - // 测试多步进的情况 - range = new DateRange(start, end, DateField.DAY_OF_YEAR, 2); - Assert.assertEquals(range.next(), DateUtil.parse("2017-01-01")); - Assert.assertEquals(range.next(), DateUtil.parse("2017-01-03")); - - // 测试不包含开始结束时间的情况 - range = new DateRange(start, end, DateField.DAY_OF_YEAR, 1, false, false); - Assert.assertEquals(range.next(), DateUtil.parse("2017-01-02")); - try { - range.next(); - Assert.fail("不包含结束时间情况下,下一个元素不应该存在!"); - } catch (NoSuchElementException ignored) { - } - } - - @Test - public void rangeToListTest() { - DateTime start = DateUtil.parse("2017-01-01"); - DateTime end = DateUtil.parse("2017-01-31"); - - List rangeToList = DateUtil.rangeToList(start, end, DateField.DAY_OF_YEAR); - Assert.assertEquals(rangeToList.get(0), DateUtil.parse("2017-01-01")); - Assert.assertEquals(rangeToList.get(1), DateUtil.parse("2017-01-02")); - } - @Test public void compareTest() { Date date1 = DateUtil.parse("2021-04-13 23:59:59.999"); diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/RangeTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/RangeTest.java index e7bd16180..c08e5dbb1 100644 --- a/hutool-core/src/test/java/cn/hutool/core/lang/RangeTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/RangeTest.java @@ -7,6 +7,9 @@ import cn.hutool.core.date.DateUtil; import org.junit.Assert; import org.junit.Test; +import java.util.List; +import java.util.NoSuchElementException; + /** * {@link Range} 单元测试 * @author Looly @@ -57,4 +60,53 @@ public class RangeTest { Assert.assertEquals(Integer.valueOf(1), range.next()); Assert.assertFalse(range.hasNext()); } + + @Test + public void rangeByStepTest() { + DateTime start = DateUtil.parse("2017-01-01"); + DateTime end = DateUtil.parse("2017-01-03"); + + // 测试包含开始和结束情况下步进为1的情况 + DateRange range = DateUtil.range(start, end, DateField.DAY_OF_YEAR); + Assert.assertEquals(range.next(), DateUtil.parse("2017-01-01")); + Assert.assertEquals(range.next(), DateUtil.parse("2017-01-02")); + Assert.assertEquals(range.next(), DateUtil.parse("2017-01-03")); + try { + range.next(); + Assert.fail("已超过边界,下一个元素不应该存在!"); + } catch (NoSuchElementException ignored) { + } + + // 测试多步进的情况 + range = new DateRange(start, end, DateField.DAY_OF_YEAR, 2); + Assert.assertEquals(DateUtil.parse("2017-01-01"), range.next()); + Assert.assertEquals(DateUtil.parse("2017-01-03"), range.next()); + } + + @Test + public void rangeDayOfYearTest(){ + DateTime start = DateUtil.parse("2017-01-01"); + DateTime end = DateUtil.parse("2017-01-05"); + + // 测试不包含开始结束时间的情况 + DateRange range = new DateRange(start, end, DateField.DAY_OF_YEAR, 1, false, false); + Assert.assertEquals(DateUtil.parse("2017-01-02"), range.next()); + Assert.assertEquals(DateUtil.parse("2017-01-03"), range.next()); + Assert.assertEquals(DateUtil.parse("2017-01-04"), range.next()); + try { + range.next(); + Assert.fail("不包含结束时间情况下,下一个元素不应该存在!"); + } catch (NoSuchElementException ignored) { + } + } + + @Test + public void rangeToListTest() { + DateTime start = DateUtil.parse("2017-01-01"); + DateTime end = DateUtil.parse("2017-01-31"); + + List rangeToList = DateUtil.rangeToList(start, end, DateField.DAY_OF_YEAR); + Assert.assertEquals(DateUtil.parse("2017-01-01"), rangeToList.get(0)); + Assert.assertEquals(DateUtil.parse("2017-01-02"), rangeToList.get(1)); + } }