fix Range

This commit is contained in:
Looly 2021-06-29 21:15:19 +08:00
parent 3ca4063ea5
commit 721fd16f4d
4 changed files with 89 additions and 76 deletions

View File

@ -52,7 +52,6 @@ public class DateRange extends Range<DateTime> {
if (dt.isAfter(end1)) {
return null;
}
return dt;
}, isIncludeStart, isIncludeEnd);
}

View File

@ -11,7 +11,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 范围生成器根据给定的初始值结束值和步进生成一个步进列表生成器<br>
* 由于用户自行实现{@link Steper}来定义步进因此Range本身无法判定边界是否达到end需在step实现边界判定逻辑
* 由于用户自行实现{@link Stepper}来定义步进因此Range本身无法判定边界是否达到end需在step实现边界判定逻辑
*
* <p>
* 此类使用{@link ReentrantReadWriteLock}保证线程安全
@ -35,10 +35,6 @@ public class Range<T> implements Iterable<T>, Iterator<T>, Serializable {
* 结束对象
*/
private final T end;
/**
* 当前对象
*/
private T current;
/**
* 下一个对象
*/
@ -46,7 +42,7 @@ public class Range<T> implements Iterable<T>, Iterator<T>, Serializable {
/**
* 步进
*/
private final Steper<T> steper;
private final Stepper<T> stepper;
/**
* 索引
*/
@ -58,27 +54,27 @@ public class Range<T> implements Iterable<T>, Iterator<T>, Serializable {
/**
* 是否包含最后一个元素
*/
private boolean includeEnd;
private final boolean includeEnd;
/**
* 构造
*
* @param start 起始对象包括
* @param steper 步进
* @param start 起始对象包括
* @param stepper 步进
*/
public Range(T start, Steper<T> steper) {
this(start, null, steper);
public Range(T start, Stepper<T> stepper) {
this(start, null, stepper);
}
/**
* 构造
*
* @param start 起始对象包含
* @param end 结束对象包含
* @param steper 步进
* @param start 起始对象包含
* @param end 结束对象包含
* @param stepper 步进
*/
public Range(T start, T end, Steper<T> steper) {
this(start, end, steper, true, true);
public Range(T start, T end, Stepper<T> stepper) {
this(start, end, stepper, true, true);
}
/**
@ -86,23 +82,22 @@ public class Range<T> implements Iterable<T>, Iterator<T>, Serializable {
*
* @param start 起始对象
* @param end 结束对象
* @param steper 步进
* @param stepper 步进
* @param isIncludeStart 是否包含第一个元素
* @param isIncludeEnd 是否包含最后一个元素
*/
public Range(T start, T end, Steper<T> steper, boolean isIncludeStart, boolean isIncludeEnd) {
public Range(T start, T end, Stepper<T> 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<T> implements Iterable<T>, Iterator<T>, 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<T> implements Iterable<T>, Iterator<T>, Serializable {
public Range<T> 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<T> implements Iterable<T>, Iterator<T>, Serializable {
* @param <T> 需要增加步进的对象
* @author Looly
*/
public interface Steper<T> {
@FunctionalInterface
public interface Stepper<T> {
/**
* 增加步进<br>
* 增加步进后的返回值如果为{@code null}则表示步进结束<br>

View File

@ -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<DateTime> 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");

View File

@ -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<DateTime> 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));
}
}