mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
fix Range
This commit is contained in:
parent
3ca4063ea5
commit
721fd16f4d
@ -52,7 +52,6 @@ public class DateRange extends Range<DateTime> {
|
|||||||
if (dt.isAfter(end1)) {
|
if (dt.isAfter(end1)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dt;
|
return dt;
|
||||||
}, isIncludeStart, isIncludeEnd);
|
}, isIncludeStart, isIncludeEnd);
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 范围生成器。根据给定的初始值、结束值和步进生成一个步进列表生成器<br>
|
* 范围生成器。根据给定的初始值、结束值和步进生成一个步进列表生成器<br>
|
||||||
* 由于用户自行实现{@link Steper}来定义步进,因此Range本身无法判定边界(是否达到end),需在step实现边界判定逻辑。
|
* 由于用户自行实现{@link Stepper}来定义步进,因此Range本身无法判定边界(是否达到end),需在step实现边界判定逻辑。
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 此类使用{@link ReentrantReadWriteLock}保证线程安全
|
* 此类使用{@link ReentrantReadWriteLock}保证线程安全
|
||||||
@ -35,10 +35,6 @@ public class Range<T> implements Iterable<T>, Iterator<T>, Serializable {
|
|||||||
* 结束对象
|
* 结束对象
|
||||||
*/
|
*/
|
||||||
private final T end;
|
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 start 起始对象(包括)
|
||||||
* @param steper 步进
|
* @param stepper 步进
|
||||||
*/
|
*/
|
||||||
public Range(T start, Steper<T> steper) {
|
public Range(T start, Stepper<T> stepper) {
|
||||||
this(start, null, steper);
|
this(start, null, stepper);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造
|
* 构造
|
||||||
*
|
*
|
||||||
* @param start 起始对象(包含)
|
* @param start 起始对象(包含)
|
||||||
* @param end 结束对象(包含)
|
* @param end 结束对象(包含)
|
||||||
* @param steper 步进
|
* @param stepper 步进
|
||||||
*/
|
*/
|
||||||
public Range(T start, T end, Steper<T> steper) {
|
public Range(T start, T end, Stepper<T> stepper) {
|
||||||
this(start, end, steper, true, true);
|
this(start, end, stepper, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,23 +82,22 @@ public class Range<T> implements Iterable<T>, Iterator<T>, Serializable {
|
|||||||
*
|
*
|
||||||
* @param start 起始对象
|
* @param start 起始对象
|
||||||
* @param end 结束对象
|
* @param end 结束对象
|
||||||
* @param steper 步进
|
* @param stepper 步进
|
||||||
* @param isIncludeStart 是否包含第一个元素
|
* @param isIncludeStart 是否包含第一个元素
|
||||||
* @param isIncludeEnd 是否包含最后一个元素
|
* @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.start = start;
|
||||||
this.current = start;
|
|
||||||
this.end = end;
|
this.end = end;
|
||||||
this.steper = steper;
|
this.stepper = stepper;
|
||||||
this.next = safeStep(this.current);
|
this.next = safeStep(this.start);
|
||||||
this.includeStart = isIncludeStart;
|
this.includeStart = isIncludeStart;
|
||||||
includeEnd = true;
|
|
||||||
this.includeEnd = isIncludeEnd;
|
this.includeEnd = isIncludeEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 禁用锁,调用此方法后不在 使用锁保护
|
* 禁用锁,调用此方法后不再使用锁保护
|
||||||
*
|
*
|
||||||
* @return this
|
* @return this
|
||||||
* @since 4.3.1
|
* @since 4.3.1
|
||||||
@ -147,30 +142,38 @@ public class Range<T> implements Iterable<T>, Iterator<T>, Serializable {
|
|||||||
* 获取下一个元素,并将下下个元素准备好
|
* 获取下一个元素,并将下下个元素准备好
|
||||||
*/
|
*/
|
||||||
private T nextUncheck() {
|
private T nextUncheck() {
|
||||||
if (0 != this.index || false == this.includeStart) {
|
T current;
|
||||||
// 非第一个元素或不包含第一个元素增加步进
|
if(0 == this.index){
|
||||||
this.current = this.next;
|
current = start;
|
||||||
if (null != this.current) {
|
if(false == this.includeStart){
|
||||||
this.next = safeStep(this.next);
|
// 获取下一组元素
|
||||||
|
index ++;
|
||||||
|
return nextUncheck();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
current = next;
|
||||||
|
this.next = safeStep(this.next);
|
||||||
}
|
}
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
return this.current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 不抛异常的获取下一步进的元素,如果获取失败返回{@code null}
|
* 不抛异常的获取下一步进的元素,如果获取失败返回{@code null}
|
||||||
*
|
*
|
||||||
* @param base 上一个元素
|
* @param base 上一个元素
|
||||||
* @return 下一步进
|
* @return 下一步进
|
||||||
*/
|
*/
|
||||||
private T safeStep(T base) {
|
private T safeStep(T base) {
|
||||||
|
final int index = this.index;
|
||||||
T next = null;
|
T next = null;
|
||||||
try {
|
try {
|
||||||
next = steper.step(base, this.end, this.index);
|
next = stepper.step(base, this.end, index);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,8 +195,8 @@ public class Range<T> implements Iterable<T>, Iterator<T>, Serializable {
|
|||||||
public Range<T> reset() {
|
public Range<T> reset() {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
this.current = this.start;
|
|
||||||
this.index = 0;
|
this.index = 0;
|
||||||
|
this.next = safeStep(this.start);
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
@ -213,7 +216,8 @@ public class Range<T> implements Iterable<T>, Iterator<T>, Serializable {
|
|||||||
* @param <T> 需要增加步进的对象
|
* @param <T> 需要增加步进的对象
|
||||||
* @author Looly
|
* @author Looly
|
||||||
*/
|
*/
|
||||||
public interface Steper<T> {
|
@FunctionalInterface
|
||||||
|
public interface Stepper<T> {
|
||||||
/**
|
/**
|
||||||
* 增加步进<br>
|
* 增加步进<br>
|
||||||
* 增加步进后的返回值如果为{@code null}则表示步进结束<br>
|
* 增加步进后的返回值如果为{@code null}则表示步进结束<br>
|
||||||
|
@ -19,7 +19,6 @@ import java.util.Date;
|
|||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
@ -681,47 +680,6 @@ public class DateUtilTest {
|
|||||||
Assert.assertEquals(Week.WEDNESDAY, week);
|
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
|
@Test
|
||||||
public void compareTest() {
|
public void compareTest() {
|
||||||
Date date1 = DateUtil.parse("2021-04-13 23:59:59.999");
|
Date date1 = DateUtil.parse("2021-04-13 23:59:59.999");
|
||||||
|
@ -7,6 +7,9 @@ import cn.hutool.core.date.DateUtil;
|
|||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link Range} 单元测试
|
* {@link Range} 单元测试
|
||||||
* @author Looly
|
* @author Looly
|
||||||
@ -57,4 +60,53 @@ public class RangeTest {
|
|||||||
Assert.assertEquals(Integer.valueOf(1), range.next());
|
Assert.assertEquals(Integer.valueOf(1), range.next());
|
||||||
Assert.assertFalse(range.hasNext());
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user