This commit is contained in:
Looly 2022-10-08 18:21:22 +08:00
parent 910caa2f06
commit 3835e6298f
11 changed files with 334 additions and 294 deletions

View File

@ -136,7 +136,7 @@ public class CompareUtil {
* <li>{@code Comparator.nullsFirst(CompareUtil.reverse())}</li> * <li>{@code Comparator.nullsFirst(CompareUtil.reverse())}</li>
* </ul> * </ul>
* *
* @param <E> 排序节点类型 * @param <E> 排序节点类型
* @param comparator 排序器 * @param comparator 排序器
* @return 默认排序器 * @return 默认排序器
* @since 6.0.0 * @since 6.0.0
@ -326,4 +326,30 @@ public class CompareUtil {
final IndexedComparator<U> indexedComparator = new IndexedComparator<>(atEndIfMiss, objs); final IndexedComparator<U> indexedComparator = new IndexedComparator<>(atEndIfMiss, objs);
return (o1, o2) -> indexedComparator.compare(keyExtractor.apply(o1), keyExtractor.apply(o2)); return (o1, o2) -> indexedComparator.compare(keyExtractor.apply(o1), keyExtractor.apply(o2));
} }
/**
* 取两个值中的最小值大小相同返回第一个值
*
* @param <T> 值类型
* @param t1 第一个值
* @param t2 第二个值
* @return 最小值
* @since 6.0.0
*/
public static <T extends Comparable<? super T>> T min(final T t1, final T t2) {
return compare(t1, t2) <= 0 ? t1 : t2;
}
/**
* 取两个值中的最大值大小相同返回第一个值
*
* @param <T> 值类型
* @param t1 第一个值
* @param t2 第二个值
* @return 最大值
* @since 6.0.0
*/
public static <T extends Comparable<? super T>> T max(final T t1, final T t2) {
return compare(t1, t2) >= 0 ? t1 : t2;
}
} }

View File

@ -1,6 +1,6 @@
package cn.hutool.core.date; package cn.hutool.core.date;
import cn.hutool.core.lang.Range; import cn.hutool.core.lang.range.Range;
import java.util.Date; import java.util.Date;

View File

@ -8,7 +8,7 @@ import java.util.function.Predicate;
/** /**
* <p>边界对象描述具有特定上界或下界的单侧无界的区间 * <p>边界对象描述具有特定上界或下界的单侧无界的区间
* *
* <h3>边界的类型</h3> * <p>边界的类型</p>
* <p>边界根据其{@link #getType()}所获得的类型可用于描述基于边界值<em>t</em>的不等式: * <p>边界根据其{@link #getType()}所获得的类型可用于描述基于边界值<em>t</em>的不等式:
* <ul> * <ul>
* <li>{@link #noneLowerBound()}{@code {x | x > -}}</li> * <li>{@link #noneLowerBound()}{@code {x | x > -}}</li>
@ -20,7 +20,7 @@ import java.util.function.Predicate;
* </ul> * </ul>
* 当作为{@link Predicate}使用时可用于判断入参对象是否能满足当前实例所对应的不等式 * 当作为{@link Predicate}使用时可用于判断入参对象是否能满足当前实例所对应的不等式
* *
* <h3>边界的比较</h3> * <p>边界的比较</p>
* <p>边界对象本身实现了{@link Comparable}接口 * <p>边界对象本身实现了{@link Comparable}接口
* 当使用{@link Comparable#compareTo}比较两个边界对象时 * 当使用{@link Comparable#compareTo}比较两个边界对象时
* 返回的比较值表示两个边界对象对应的点在实数轴上从左到右的先后顺序<br> * 返回的比较值表示两个边界对象对应的点在实数轴上从左到右的先后顺序<br>
@ -41,27 +41,16 @@ import java.util.function.Predicate;
public interface Bound<T extends Comparable<? super T>> extends Predicate<T>, Comparable<Bound<T>> { public interface Bound<T extends Comparable<? super T>> extends Predicate<T>, Comparable<Bound<T>> {
/** /**
* 无穷小 * 无穷小的描述
*/ */
String INFINITE_MIN = "-\u221e"; String INFINITE_MIN = "-\u221e";
/** /**
* 无穷大 * 无穷大的藐视
*/ */
String INFINITE_MAX = "+\u221e"; String INFINITE_MAX = "+\u221e";
/** // region --------------- static methods
* 无限小的左边界
*/
@SuppressWarnings("rawtypes")
NoneLowerBound NONE_LOWER_BOUND = new NoneLowerBound();
/**
* 无限大的右边界
*/
@SuppressWarnings("rawtypes")
NoneUpperBound NONE_UPPER_BOUND = new NoneUpperBound();
/** /**
* {@code {x | x > -}} * {@code {x | x > -}}
* *
@ -70,7 +59,7 @@ public interface Bound<T extends Comparable<? super T>> extends Predicate<T>, Co
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static <T extends Comparable<? super T>> Bound<T> noneLowerBound() { static <T extends Comparable<? super T>> Bound<T> noneLowerBound() {
return NONE_LOWER_BOUND; return NoneLowerBound.INSTANCE;
} }
/** /**
@ -81,7 +70,7 @@ public interface Bound<T extends Comparable<? super T>> extends Predicate<T>, Co
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static <T extends Comparable<? super T>> Bound<T> noneUpperBound() { static <T extends Comparable<? super T>> Bound<T> noneUpperBound() {
return NONE_UPPER_BOUND; return NoneUpperBound.INSTANCE;
} }
/** /**
@ -127,6 +116,7 @@ public interface Bound<T extends Comparable<? super T>> extends Predicate<T>, Co
static <T extends Comparable<? super T>> Bound<T> atMost(final T max) { static <T extends Comparable<? super T>> Bound<T> atMost(final T max) {
return new FiniteBound<>(Objects.requireNonNull(max), BoundType.CLOSE_UPPER_BOUND); return new FiniteBound<>(Objects.requireNonNull(max), BoundType.CLOSE_UPPER_BOUND);
} }
// endregion --------------- static methods
/** /**
* 获取边界值 * 获取边界值
@ -148,6 +138,7 @@ public interface Bound<T extends Comparable<? super T>> extends Predicate<T>, Co
* @param t 要检验的值不允许为{@code null} * @param t 要检验的值不允许为{@code null}
* @return 是否 * @return 是否
*/ */
@SuppressWarnings("AbstractMethodOverridesAbstractMethod")
@Override @Override
boolean test(T t); boolean test(T t);
@ -163,6 +154,7 @@ public interface Bound<T extends Comparable<? super T>> extends Predicate<T>, Co
* @param bound 边界 * @param bound 边界
* @return 位置 * @return 位置
*/ */
@SuppressWarnings("AbstractMethodOverridesAbstractMethod")
@Override @Override
int compareTo(final Bound<T> bound); int compareTo(final Bound<T> bound);
@ -277,11 +269,11 @@ public interface Bound<T extends Comparable<? super T>> extends Predicate<T>, Co
@Override @Override
public int compareTo(final Bound<T> bound) { public int compareTo(final Bound<T> bound) {
// 另一边界为无限小的左边界则当前边界必然靠后 // 另一边界为无限小的左边界则当前边界必然靠后
if (bound instanceof Bound.NoneLowerBound) { if (bound instanceof NoneLowerBound) {
return 1; return 1;
} }
// 另一边界为无限大的右边界则当前边界必然靠前 // 另一边界为无限大的右边界则当前边界必然靠前
if (bound instanceof Bound.NoneUpperBound) { if (bound instanceof NoneUpperBound) {
return -1; return -1;
} }
// 两值不相等直接比较边界值 // 两值不相等直接比较边界值
@ -307,8 +299,7 @@ public interface Bound<T extends Comparable<? super T>> extends Predicate<T>, Co
return bt1.isLowerBound() ? 1 : -1; return bt1.isLowerBound() ? 1 : -1;
} }
// 都为左边界则封闭边界在前若都为右边界则封闭边界在后 // 都为左边界则封闭边界在前若都为右边界则封闭边界在后
return bt1.isLowerBound() ? return Integer.compare(bt1.getCode(), bt2.getCode());
Integer.compare(bt1.getCode(), bt2.getCode()) : Integer.compare(bt1.getCode(), bt2.getCode());
} }
/** /**
@ -383,205 +374,4 @@ public interface Bound<T extends Comparable<? super T>> extends Predicate<T>, Co
); );
} }
} }
/**
* 无限小的左边界
*
* @param <T> 边界值类型
*/
class NoneLowerBound<T extends Comparable<? super T>> implements Bound<T> {
private NoneLowerBound() {
}
/**
* 获取边界值
*
* @return 边界值
*/
@Override
public T getValue() {
return null;
}
/**
* 获取边界类型
*
* @return 边界类型
*/
@Override
public BoundType getType() {
return BoundType.OPEN_LOWER_BOUND;
}
/**
* 检验指定值是否在当前边界表示的范围内
*
* @param t 要检验的值不允许为{@code null}
* @return 是否
*/
@Override
public boolean test(final T t) {
return true;
}
/**
* <p>比较另一边界与当前边界在坐标轴上位置的先后顺序<br>
* 若令当前边界为<em>t1</em>另一边界为<em>t2</em>则有
* <ul>
* <li>-1<em>t1</em><em>t2</em>的左侧</li>
* <li>0<em>t1</em><em>t2</em>的重合</li>
* <li>-1<em>t1</em><em>t2</em>的右侧</li>
* </ul>
*
* @param bound 边界
* @return 位置
*/
@Override
public int compareTo(final Bound<T> bound) {
return bound instanceof Bound.NoneLowerBound ? 0 : -1;
}
/**
* 获取{@code "[value"}{@code "(value"}格式的字符串
*
* @return 字符串
*/
@Override
public String descBound() {
return getType().getSymbol() + INFINITE_MIN;
}
/**
* 对当前边界取反
*
* @return 取反后的边界
*/
@Override
public Bound<T> negate() {
return this;
}
/**
* 将当前实例转为一个区间
*
* @return 区间
*/
@Override
public BoundedRange<T> toRange() {
return BoundedRange.all();
}
/**
* 获得当前实例对应的{@code { x | x >= xxx}}格式的不等式字符串
*
* @return 字符串
*/
@Override
public String toString() {
return "{x | x > -\u221e}";
}
}
/**
* 无限大的右边界
*
* @param <T> 边界值类型
*/
class NoneUpperBound<T extends Comparable<? super T>> implements Bound<T> {
private NoneUpperBound() {
}
/**
* 获取边界值
*
* @return 边界值
*/
@Override
public T getValue() {
return null;
}
/**
* 获取边界类型
*
* @return 边界类型
*/
@Override
public BoundType getType() {
return BoundType.OPEN_UPPER_BOUND;
}
/**
* 检验指定值是否在当前边界表示的范围内
*
* @param t 要检验的值不允许为{@code null}
* @return 是否
*/
@Override
public boolean test(final T t) {
return true;
}
/**
* <p>比较另一边界与当前边界在坐标轴上位置的先后顺序<br>
* 若令当前边界为<em>t1</em>另一边界为<em>t2</em>则有
* <ul>
* <li>-1<em>t1</em><em>t2</em>的左侧</li>
* <li>0<em>t1</em><em>t2</em>的重合</li>
* <li>-1<em>t1</em><em>t2</em>的右侧</li>
* </ul>
*
* @param bound 边界
* @return 位置
*/
@Override
public int compareTo(final Bound<T> bound) {
return bound instanceof Bound.NoneUpperBound ? 0 : 1;
}
/**
* 获取{@code "[value"}{@code "(value"}格式的字符串
*
* @return 字符串
*/
@Override
public String descBound() {
return INFINITE_MAX + getType().getSymbol();
}
/**
* 获得当前实例对应的{@code { x | x >= xxx}}格式的不等式字符串
*
* @return 字符串
*/
@Override
public String toString() {
return "{x | x < +\u221e}";
}
/**
* 对当前边界取反
*
* @return 取反后的边界
*/
@Override
public Bound<T> negate() {
return this;
}
/**
* 将当前实例转为一个区间
*
* @return 区间
*/
@Override
public BoundedRange<T> toRange() {
return BoundedRange.all();
}
}
} }

View File

@ -1,7 +1,7 @@
package cn.hutool.core.lang.range; package cn.hutool.core.lang.range;
/** /**
* 边界类型 * 边界类型枚举
* *
* @author huangchengxing * @author huangchengxing
* @since 6.0.0 * @since 6.0.0
@ -45,6 +45,9 @@ public enum BoundType {
/** /**
* 构造 * 构造
* @param symbol 符号`[``(`
* @param operator 运算符`<`
* @param code 是否为开区间
*/ */
BoundType(final String symbol, final String operator, final int code) { BoundType(final String symbol, final String operator, final int code) {
this.symbol = symbol; this.symbol = symbol;
@ -85,7 +88,7 @@ public enum BoundType {
* @param boundType 另一边界类型 * @param boundType 另一边界类型
* @return 是否 * @return 是否
*/ */
public boolean isDislocated(BoundType boundType) { public boolean isDislocated(final BoundType boundType) {
return code * boundType.code < 0; return code * boundType.code < 0;
} }

View File

@ -1,5 +1,6 @@
package cn.hutool.core.lang.range; package cn.hutool.core.lang.range;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Opt; import cn.hutool.core.lang.Opt;
@ -10,8 +11,8 @@ import java.util.function.Predicate;
* <p>参考<em>Guava</em><em>Range</em>实现用于描述作为上下界的两个{@link Bound}实例围成的一段区间<br> * <p>参考<em>Guava</em><em>Range</em>实现用于描述作为上下界的两个{@link Bound}实例围成的一段区间<br>
* 作为{@link Predicate}使用时可检验指定值是否在区间中即指定值是否同时满足上下界的{@link Bound#test}方法 * 作为{@link Predicate}使用时可检验指定值是否在区间中即指定值是否同时满足上下界的{@link Bound#test}方法
* *
* <h3>区间的类型</h3> * <p>区间的类型支持通过工厂方法创建下述几种类型的区间</p>
* <p>支持通过工厂方法创建下述几种类型的区间 * <table summary="">
* <tr><th>区间 <th>数学定义 <th>工厂方法 * <tr><th>区间 <th>数学定义 <th>工厂方法
* <tr><td>{@code (a, b)} <td>{@code {x | a < x < b}} <td>{@link #open} * <tr><td>{@code (a, b)} <td>{@code {x | a < x < b}} <td>{@link #open}
* <tr><td>{@code [a, b]} <td>{@code {x | a <= x <= b}}<td>{@link #close} * <tr><td>{@code [a, b]} <td>{@code {x | a <= x <= b}}<td>{@link #close}
@ -24,7 +25,7 @@ import java.util.function.Predicate;
* <tr><td>{@code (-, +)}<td>{@code {x}} <td>{@link #all} * <tr><td>{@code (-, +)}<td>{@code {x}} <td>{@link #all}
* </table> * </table>
* *
* <h3>空区间</h3> * <p>空区间</p>
* <p>根据数学定义当区间中无任何实数时认为该区间代表的集合为空集 * <p>根据数学定义当区间中无任何实数时认为该区间代表的集合为空集
* 用户可通过{@link #isEmpty}确认当前实例是否为空区间<br> * 用户可通过{@link #isEmpty}确认当前实例是否为空区间<br>
* 若实例上界<em>a</em>下界为<em>b</em>则当实例满足下述任意条件时认为其为一个空区间 * 若实例上界<em>a</em>下界为<em>b</em>则当实例满足下述任意条件时认为其为一个空区间
@ -49,7 +50,7 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
/** /**
* 双向无界的区间 * 双向无界的区间
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings({"rawtypes", "unchecked"})
private static final BoundedRange ALL = new BoundedRange(Bound.noneLowerBound(), Bound.noneUpperBound()); private static final BoundedRange ALL = new BoundedRange(Bound.noneLowerBound(), Bound.noneUpperBound());
/** /**
@ -80,15 +81,15 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
* @param <T> 边界值类型 * @param <T> 边界值类型
* @return 区间 * @return 区间
* @throws IllegalArgumentException 当创建的区间表示的集合为空时抛出 * @throws IllegalArgumentException 当创建的区间表示的集合为空时抛出
* @throws NullPointerException 上界或下界为{@code null}时抛出 * @throws NullPointerException 上界或下界为{@code null}时抛出
*/ */
static <T extends Comparable<? super T>> BoundedRange<T> close(final T lowerBound, final T upperBound) { static <T extends Comparable<? super T>> BoundedRange<T> close(final T lowerBound, final T upperBound) {
Objects.requireNonNull(lowerBound); Objects.requireNonNull(lowerBound);
Objects.requireNonNull(upperBound); Objects.requireNonNull(upperBound);
return checkEmpty( return checkEmpty(
new BoundedRange<>( new BoundedRange<>(
Bound.atLeast(lowerBound), Bound.atMost(upperBound) Bound.atLeast(lowerBound), Bound.atMost(upperBound)
) )
); );
} }
@ -100,13 +101,13 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
* @param <T> 边界值类型 * @param <T> 边界值类型
* @return 区间 * @return 区间
* @throws IllegalArgumentException 当创建的区间表示的集合为空时抛出 * @throws IllegalArgumentException 当创建的区间表示的集合为空时抛出
* @throws NullPointerException 上界或下界为{@code null}时抛出 * @throws NullPointerException 上界或下界为{@code null}时抛出
*/ */
static <T extends Comparable<? super T>> BoundedRange<T> open(final T lowerBound, final T upperBound) { static <T extends Comparable<? super T>> BoundedRange<T> open(final T lowerBound, final T upperBound) {
Objects.requireNonNull(lowerBound); Objects.requireNonNull(lowerBound);
Objects.requireNonNull(upperBound); Objects.requireNonNull(upperBound);
return checkEmpty( return checkEmpty(
new BoundedRange<>(Bound.greaterThan(lowerBound), Bound.lessThan(upperBound)) new BoundedRange<>(Bound.greaterThan(lowerBound), Bound.lessThan(upperBound))
); );
} }
@ -118,16 +119,16 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
* @param <T> 边界值类型 * @param <T> 边界值类型
* @return 区间 * @return 区间
* @throws IllegalArgumentException 当创建的区间表示的集合为空时抛出 * @throws IllegalArgumentException 当创建的区间表示的集合为空时抛出
* @throws NullPointerException 上界或下界为{@code null}时抛出 * @throws NullPointerException 上界或下界为{@code null}时抛出
*/ */
static <T extends Comparable<? super T>> BoundedRange<T> closeOpen(final T lowerBound, final T upperBound) { static <T extends Comparable<? super T>> BoundedRange<T> closeOpen(final T lowerBound, final T upperBound) {
Objects.requireNonNull(lowerBound); Objects.requireNonNull(lowerBound);
Objects.requireNonNull(upperBound); Objects.requireNonNull(upperBound);
return checkEmpty( return checkEmpty(
new BoundedRange<>( new BoundedRange<>(
Bound.atLeast(lowerBound), Bound.atLeast(lowerBound),
Bound.lessThan(upperBound) Bound.lessThan(upperBound)
) )
); );
} }
@ -139,16 +140,16 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
* @param <T> 边界值类型 * @param <T> 边界值类型
* @return 区间 * @return 区间
* @throws IllegalArgumentException 当创建的区间表示的集合为空时抛出 * @throws IllegalArgumentException 当创建的区间表示的集合为空时抛出
* @throws NullPointerException 上界或下界为{@code null}时抛出 * @throws NullPointerException 上界或下界为{@code null}时抛出
*/ */
static <T extends Comparable<? super T>> BoundedRange<T> openClose(final T lowerBound, final T upperBound) { static <T extends Comparable<? super T>> BoundedRange<T> openClose(final T lowerBound, final T upperBound) {
Objects.requireNonNull(lowerBound); Objects.requireNonNull(lowerBound);
Objects.requireNonNull(upperBound); Objects.requireNonNull(upperBound);
return checkEmpty( return checkEmpty(
new BoundedRange<>( new BoundedRange<>(
Bound.greaterThan(lowerBound), Bound.greaterThan(lowerBound),
Bound.atMost(upperBound) Bound.atMost(upperBound)
) )
); );
} }
@ -287,19 +288,19 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
* @return 是否 * @return 是否
*/ */
public boolean isEmpty() { public boolean isEmpty() {
Bound<T> low = getLowerBound(); final Bound<T> low = getLowerBound();
Bound<T> up = getUpperBound(); final Bound<T> up = getUpperBound();
if (low instanceof Bound.NoneLowerBound || up instanceof Bound.NoneUpperBound) { if (low instanceof NoneLowerBound || up instanceof NoneUpperBound) {
return false; return false;
} }
int compareValue = low.getValue().compareTo(up.getValue()); final int compareValue = low.getValue().compareTo(up.getValue());
if (compareValue < 0) { if (compareValue < 0) {
return false; return false;
} }
// 上界小于下界时为空 // 上界小于下界时为空
return compareValue > 0 return compareValue > 0
// 上下界的边界值相等且不为退化区间是为空 // 上下界的边界值相等且不为退化区间是为空
|| !(low.getType().isClose() && up.getType().isClose()); || !(low.getType().isClose() && up.getType().isClose());
} }
/** /**
@ -326,7 +327,7 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
if (o == null || getClass() != o.getClass()) { if (o == null || getClass() != o.getClass()) {
return false; return false;
} }
final BoundedRange<?> that = (BoundedRange<?>)o; final BoundedRange<?> that = (BoundedRange<?>) o;
return lowerBound.equals(that.lowerBound) && upperBound.equals(that.upperBound); return lowerBound.equals(that.lowerBound) && upperBound.equals(that.upperBound);
} }
@ -352,7 +353,7 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
*/ */
public boolean isSuperset(final BoundedRange<T> other) { public boolean isSuperset(final BoundedRange<T> other) {
return getLowerBound().compareTo(other.getLowerBound()) <= 0 return getLowerBound().compareTo(other.getLowerBound()) <= 0
&& getUpperBound().compareTo(other.getUpperBound()) >= 0; && getUpperBound().compareTo(other.getUpperBound()) >= 0;
} }
/** /**
@ -363,7 +364,7 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
*/ */
public boolean isProperSuperset(final BoundedRange<T> other) { public boolean isProperSuperset(final BoundedRange<T> other) {
return getLowerBound().compareTo(other.getLowerBound()) < 0 return getLowerBound().compareTo(other.getLowerBound()) < 0
&& getUpperBound().compareTo(other.getUpperBound()) > 0; && getUpperBound().compareTo(other.getUpperBound()) > 0;
} }
/** /**
@ -374,7 +375,7 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
*/ */
public boolean isSubset(final BoundedRange<T> other) { public boolean isSubset(final BoundedRange<T> other) {
return getLowerBound().compareTo(other.getLowerBound()) >= 0 return getLowerBound().compareTo(other.getLowerBound()) >= 0
&& getUpperBound().compareTo(other.getUpperBound()) <= 0; && getUpperBound().compareTo(other.getUpperBound()) <= 0;
} }
/** /**
@ -385,7 +386,7 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
*/ */
public boolean isProperSubset(final BoundedRange<T> other) { public boolean isProperSubset(final BoundedRange<T> other) {
return getLowerBound().compareTo(other.getLowerBound()) > 0 return getLowerBound().compareTo(other.getLowerBound()) > 0
&& getUpperBound().compareTo(other.getUpperBound()) < 0; && getUpperBound().compareTo(other.getUpperBound()) < 0;
} }
/** /**
@ -396,7 +397,7 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
*/ */
public boolean isDisjoint(final BoundedRange<T> other) { public boolean isDisjoint(final BoundedRange<T> other) {
return getLowerBound().compareTo(other.getUpperBound()) > 0 return getLowerBound().compareTo(other.getUpperBound()) > 0
|| getUpperBound().compareTo(other.getLowerBound()) < 0; || getUpperBound().compareTo(other.getLowerBound()) < 0;
} }
/** /**
@ -418,7 +419,7 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
public boolean isEquals(final BoundedRange<T> other) { public boolean isEquals(final BoundedRange<T> other) {
Objects.requireNonNull(other); Objects.requireNonNull(other);
return other.getLowerBound().compareTo(getLowerBound()) == 0 return other.getLowerBound().compareTo(getLowerBound()) == 0
&& other.getUpperBound().compareTo(getUpperBound()) == 0; && other.getUpperBound().compareTo(getUpperBound()) == 0;
} }
/** /**
@ -430,8 +431,8 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
@Override @Override
public boolean test(final T value) { public boolean test(final T value) {
return getLowerBound() return getLowerBound()
.and(getUpperBound()) .and(getUpperBound())
.test(value); .test(value);
} }
// endregion // endregion
@ -450,8 +451,8 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
return this; return this;
} }
return new BoundedRange<>( return new BoundedRange<>(
getMin(getLowerBound(), other.getLowerBound()), CompareUtil.min(getLowerBound(), other.getLowerBound()),
getMax(getUpperBound(), other.getUpperBound()) CompareUtil.max(getUpperBound(), other.getUpperBound())
); );
} }
@ -464,8 +465,8 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
public BoundedRange<T> span(final BoundedRange<T> other) { public BoundedRange<T> span(final BoundedRange<T> other) {
Objects.requireNonNull(other); Objects.requireNonNull(other);
return new BoundedRange<>( return new BoundedRange<>(
getMin(getLowerBound(), other.getLowerBound()), CompareUtil.min(getLowerBound(), other.getLowerBound()),
getMax(getUpperBound(), other.getUpperBound()) CompareUtil.max(getUpperBound(), other.getUpperBound())
); );
} }
@ -481,8 +482,8 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
return null; return null;
} }
return new BoundedRange<>( return new BoundedRange<>(
getMin(getUpperBound(), other.getUpperBound()).negate(), CompareUtil.min(getUpperBound(), other.getUpperBound()).negate(),
getMax(getLowerBound(), other.getLowerBound()).negate() CompareUtil.max(getLowerBound(), other.getLowerBound()).negate()
); );
} }
@ -498,8 +499,8 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
return null; return null;
} }
return new BoundedRange<>( return new BoundedRange<>(
getMax(getLowerBound(), other.getLowerBound()), CompareUtil.min(getLowerBound(), other.getLowerBound()),
getMin(getUpperBound(), other.getUpperBound()) CompareUtil.max(getUpperBound(), other.getUpperBound())
); );
} }
@ -511,9 +512,9 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
*/ */
public BoundedRange<T> subGreatThan(final T min) { public BoundedRange<T> subGreatThan(final T min) {
return Opt.ofNullable(min) return Opt.ofNullable(min)
.filter(this) .filter(this)
.map(t -> new BoundedRange<>(Bound.greaterThan(t), getUpperBound())) .map(t -> new BoundedRange<>(Bound.greaterThan(t), getUpperBound()))
.orElse(this); .orElse(this);
} }
/** /**
@ -524,9 +525,9 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
*/ */
public BoundedRange<T> subAtLeast(final T min) { public BoundedRange<T> subAtLeast(final T min) {
return Opt.ofNullable(min) return Opt.ofNullable(min)
.filter(this) .filter(this)
.map(t -> new BoundedRange<>(Bound.atLeast(t), getUpperBound())) .map(t -> new BoundedRange<>(Bound.atLeast(t), getUpperBound()))
.orElse(this); .orElse(this);
} }
/** /**
@ -537,9 +538,9 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
*/ */
public BoundedRange<T> subLessThan(final T max) { public BoundedRange<T> subLessThan(final T max) {
return Opt.ofNullable(max) return Opt.ofNullable(max)
.filter(this) .filter(this)
.map(t -> new BoundedRange<>(getLowerBound(), Bound.lessThan(max))) .map(t -> new BoundedRange<>(getLowerBound(), Bound.lessThan(max)))
.orElse(this); .orElse(this);
} }
/** /**
@ -550,22 +551,14 @@ public class BoundedRange<T extends Comparable<? super T>> implements Predicate<
*/ */
public BoundedRange<T> subAtMost(final T max) { public BoundedRange<T> subAtMost(final T max) {
return Opt.ofNullable(max) return Opt.ofNullable(max)
.filter(this) .filter(this)
.map(t -> new BoundedRange<>(getLowerBound(), Bound.atMost(max))) .map(t -> new BoundedRange<>(getLowerBound(), Bound.atMost(max)))
.orElse(this); .orElse(this);
} }
// endregion // endregion
private static <T extends Comparable<? super T>> Bound<T> getMin(Bound<T> b1, Bound<T> b2) { private static <T extends Comparable<? super T>> BoundedRange<T> checkEmpty(final BoundedRange<T> range) {
return b1.compareTo(b2) <= 0 ? b1 : b2;
}
private static <T extends Comparable<? super T>> Bound<T> getMax(Bound<T> b1, Bound<T> b2) {
return b1.compareTo(b2) >= 0 ? b1 : b2;
}
private static <T extends Comparable<? super T>> BoundedRange<T> checkEmpty(BoundedRange<T> range) {
Assert.isFalse(range.isEmpty(), "{} is a empty range", range); Assert.isFalse(range.isEmpty(), "{} is a empty range", range);
return range; return range;
} }

View File

@ -0,0 +1,108 @@
package cn.hutool.core.lang.range;
/**
* 无限小的左边界
*
* @param <T> 边界值类型
* @author huangchengxing
* @since 6.0.0
*/
class NoneLowerBound<T extends Comparable<? super T>> implements Bound<T> {
/**
* 无限小的左边界单例
*/
@SuppressWarnings("rawtypes")
static final NoneLowerBound INSTANCE = new NoneLowerBound();
private NoneLowerBound() {
}
/**
* 获取边界值
*
* @return 边界值
*/
@Override
public T getValue() {
return null;
}
/**
* 获取边界类型
*
* @return 边界类型
*/
@Override
public BoundType getType() {
return BoundType.OPEN_LOWER_BOUND;
}
/**
* 检验指定值是否在当前边界表示的范围内
*
* @param t 要检验的值不允许为{@code null}
* @return 是否
*/
@Override
public boolean test(final T t) {
return true;
}
/**
* <p>比较另一边界与当前边界在坐标轴上位置的先后顺序<br>
* 若令当前边界为<em>t1</em>另一边界为<em>t2</em>则有
* <ul>
* <li>-1<em>t1</em><em>t2</em>的左侧</li>
* <li>0<em>t1</em><em>t2</em>的重合</li>
* <li>-1<em>t1</em><em>t2</em>的右侧</li>
* </ul>
*
* @param bound 边界
* @return 位置
*/
@Override
public int compareTo(final Bound<T> bound) {
return bound instanceof NoneLowerBound ? 0 : -1;
}
/**
* 获取{@code "[value"}{@code "(value"}格式的字符串
*
* @return 字符串
*/
@Override
public String descBound() {
return getType().getSymbol() + INFINITE_MIN;
}
/**
* 对当前边界取反
*
* @return 取反后的边界
*/
@Override
public Bound<T> negate() {
return this;
}
/**
* 将当前实例转为一个区间
*
* @return 区间
*/
@Override
public BoundedRange<T> toRange() {
return BoundedRange.all();
}
/**
* 获得当前实例对应的{@code { x | x >= xxx}}格式的不等式字符串
*
* @return 字符串
*/
@Override
public String toString() {
return "{x | x > -\u221e}";
}
}

View File

@ -0,0 +1,106 @@
package cn.hutool.core.lang.range;
/**
* 无限大的右边界
*
* @param <T> 边界值类型
*/
class NoneUpperBound<T extends Comparable<? super T>> implements Bound<T> {
/**
* 无限大的右边界
*/
@SuppressWarnings("rawtypes")
static final NoneUpperBound INSTANCE = new NoneUpperBound();
private NoneUpperBound() {
}
/**
* 获取边界值
*
* @return 边界值
*/
@Override
public T getValue() {
return null;
}
/**
* 获取边界类型
*
* @return 边界类型
*/
@Override
public BoundType getType() {
return BoundType.OPEN_UPPER_BOUND;
}
/**
* 检验指定值是否在当前边界表示的范围内
*
* @param t 要检验的值不允许为{@code null}
* @return 是否
*/
@Override
public boolean test(final T t) {
return true;
}
/**
* <p>比较另一边界与当前边界在坐标轴上位置的先后顺序<br>
* 若令当前边界为<em>t1</em>另一边界为<em>t2</em>则有
* <ul>
* <li>-1<em>t1</em><em>t2</em>的左侧</li>
* <li>0<em>t1</em><em>t2</em>的重合</li>
* <li>-1<em>t1</em><em>t2</em>的右侧</li>
* </ul>
*
* @param bound 边界
* @return 位置
*/
@Override
public int compareTo(final Bound<T> bound) {
return bound instanceof NoneUpperBound ? 0 : 1;
}
/**
* 获取{@code "[value"}{@code "(value"}格式的字符串
*
* @return 字符串
*/
@Override
public String descBound() {
return INFINITE_MAX + getType().getSymbol();
}
/**
* 获得当前实例对应的{@code { x | x >= xxx}}格式的不等式字符串
*
* @return 字符串
*/
@Override
public String toString() {
return "{x | x < +\u221e}";
}
/**
* 对当前边界取反
*
* @return 取反后的边界
*/
@Override
public Bound<T> negate() {
return this;
}
/**
* 将当前实例转为一个区间
*
* @return 区间
*/
@Override
public BoundedRange<T> toRange() {
return BoundedRange.all();
}
}

View File

@ -1,5 +1,6 @@
package cn.hutool.core.lang; package cn.hutool.core.lang.range;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.thread.lock.NoLock; import cn.hutool.core.thread.lock.NoLock;
import java.io.Serializable; import java.io.Serializable;

View File

@ -0,0 +1,10 @@
/**
* 提供区间和边界封装主要包括
* <ul>
* <li>{@link cn.hutool.core.lang.range.Bound}: 提供边界的抽象表示包括边界范围开闭区间等</li>
* <li>{@link cn.hutool.core.lang.range.Range}: 提供可迭代的区间</li>
* </ul>
*
* @author huangchengxing, looly
*/
package cn.hutool.core.lang.range;

View File

@ -1394,7 +1394,8 @@ public class ArrayUtil extends PrimitiveArrayUtil {
* @return 最小值 * @return 最小值
* @since 3.0.9 * @since 3.0.9
*/ */
public static <T extends Comparable<? super T>> T min(final T[] numberArray) { @SafeVarargs
public static <T extends Comparable<? super T>> T min(final T... numberArray) {
return min(numberArray, null); return min(numberArray, null);
} }
@ -1428,7 +1429,8 @@ public class ArrayUtil extends PrimitiveArrayUtil {
* @return 最大值 * @return 最大值
* @since 3.0.9 * @since 3.0.9
*/ */
public static <T extends Comparable<? super T>> T max(final T[] numberArray) { @SafeVarargs
public static <T extends Comparable<? super T>> T max(final T... numberArray) {
return max(numberArray, null); return max(numberArray, null);
} }

View File

@ -4,6 +4,7 @@ import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateRange; import cn.hutool.core.date.DateRange;
import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.range.Range;
import cn.hutool.core.text.StrUtil; import cn.hutool.core.text.StrUtil;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;