diff --git a/hutool-core/src/main/java/cn/hutool/core/comparator/CompareUtil.java b/hutool-core/src/main/java/cn/hutool/core/comparator/CompareUtil.java index bbd723284..ce85293c4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/comparator/CompareUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/comparator/CompareUtil.java @@ -136,7 +136,7 @@ public class CompareUtil { *
  • {@code Comparator.nullsFirst(CompareUtil.reverse())}
  • * * - * @param 排序节点类型 + * @param 排序节点类型 * @param comparator 排序器 * @return 默认排序器 * @since 6.0.0 @@ -326,4 +326,30 @@ public class CompareUtil { final IndexedComparator indexedComparator = new IndexedComparator<>(atEndIfMiss, objs); return (o1, o2) -> indexedComparator.compare(keyExtractor.apply(o1), keyExtractor.apply(o2)); } + + /** + * 取两个值中的最小值,大小相同返回第一个值 + * + * @param 值类型 + * @param t1 第一个值 + * @param t2 第二个值 + * @return 最小值 + * @since 6.0.0 + */ + public static > T min(final T t1, final T t2) { + return compare(t1, t2) <= 0 ? t1 : t2; + } + + /** + * 取两个值中的最大值,大小相同返回第一个值 + * + * @param 值类型 + * @param t1 第一个值 + * @param t2 第二个值 + * @return 最大值 + * @since 6.0.0 + */ + public static > T max(final T t1, final T t2) { + return compare(t1, t2) >= 0 ? t1 : t2; + } } 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 26c04f8e1..2241d7091 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 @@ -1,6 +1,6 @@ package cn.hutool.core.date; -import cn.hutool.core.lang.Range; +import cn.hutool.core.lang.range.Range; import java.util.Date; diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/range/Bound.java b/hutool-core/src/main/java/cn/hutool/core/lang/range/Bound.java index 105d51f13..c26a559b7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/range/Bound.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/range/Bound.java @@ -8,7 +8,7 @@ import java.util.function.Predicate; /** *

    边界对象,描述具有特定上界或下界的单侧无界的区间。 * - *

    边界的类型

    + *

    边界的类型

    *

    边界根据其{@link #getType()}所获得的类型,可用于描述基于边界值t的不等式: *

      *
    • {@link #noneLowerBound()}:{@code {x | x > -∞}};
    • @@ -20,7 +20,7 @@ import java.util.function.Predicate; *
    * 当作为{@link Predicate}使用时,可用于判断入参对象是否能满足当前实例所对应的不等式。 * - *

    边界的比较

    + *

    边界的比较

    *

    边界对象本身实现了{@link Comparable}接口, * 当使用{@link Comparable#compareTo}比较两个边界对象时, * 返回的比较值表示两个边界对象对应的点在实数轴上从左到右的先后顺序。
    @@ -41,27 +41,16 @@ import java.util.function.Predicate; public interface Bound> extends Predicate, Comparable> { /** - * 无穷小 + * 无穷小的描述 */ String INFINITE_MIN = "-\u221e"; /** - * 无穷大 + * 无穷大的藐视 */ String INFINITE_MAX = "+\u221e"; - /** - * 无限小的左边界 - */ - @SuppressWarnings("rawtypes") - NoneLowerBound NONE_LOWER_BOUND = new NoneLowerBound(); - - /** - * 无限大的右边界 - */ - @SuppressWarnings("rawtypes") - NoneUpperBound NONE_UPPER_BOUND = new NoneUpperBound(); - + // region --------------- static methods /** * {@code {x | x > -∞}} * @@ -70,7 +59,7 @@ public interface Bound> extends Predicate, Co */ @SuppressWarnings("unchecked") static > Bound noneLowerBound() { - return NONE_LOWER_BOUND; + return NoneLowerBound.INSTANCE; } /** @@ -81,7 +70,7 @@ public interface Bound> extends Predicate, Co */ @SuppressWarnings("unchecked") static > Bound noneUpperBound() { - return NONE_UPPER_BOUND; + return NoneUpperBound.INSTANCE; } /** @@ -127,6 +116,7 @@ public interface Bound> extends Predicate, Co static > Bound atMost(final T max) { return new FiniteBound<>(Objects.requireNonNull(max), BoundType.CLOSE_UPPER_BOUND); } + // endregion --------------- static methods /** * 获取边界值 @@ -148,6 +138,7 @@ public interface Bound> extends Predicate, Co * @param t 要检验的值,不允许为{@code null} * @return 是否 */ + @SuppressWarnings("AbstractMethodOverridesAbstractMethod") @Override boolean test(T t); @@ -163,6 +154,7 @@ public interface Bound> extends Predicate, Co * @param bound 边界 * @return 位置 */ + @SuppressWarnings("AbstractMethodOverridesAbstractMethod") @Override int compareTo(final Bound bound); @@ -277,11 +269,11 @@ public interface Bound> extends Predicate, Co @Override public int compareTo(final Bound bound) { // 另一边界为无限小的左边界,则当前边界必然靠后 - if (bound instanceof Bound.NoneLowerBound) { + if (bound instanceof NoneLowerBound) { return 1; } // 另一边界为无限大的右边界,则当前边界必然靠前 - if (bound instanceof Bound.NoneUpperBound) { + if (bound instanceof NoneUpperBound) { return -1; } // 两值不相等,直接比较边界值 @@ -307,8 +299,7 @@ public interface Bound> extends Predicate, Co return bt1.isLowerBound() ? 1 : -1; } // 都为左边界,则封闭边界在前,若都为右边界,则封闭边界在后 - return bt1.isLowerBound() ? - Integer.compare(bt1.getCode(), bt2.getCode()) : Integer.compare(bt1.getCode(), bt2.getCode()); + return Integer.compare(bt1.getCode(), bt2.getCode()); } /** @@ -383,205 +374,4 @@ public interface Bound> extends Predicate, Co ); } } - - /** - * 无限小的左边界 - * - * @param 边界值类型 - */ - class NoneLowerBound> implements Bound { - - 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; - } - - /** - *

    比较另一边界与当前边界在坐标轴上位置的先后顺序。
    - * 若令当前边界为t1,另一边界为t2,则有 - *

      - *
    • -1:t1t2的左侧;
    • - *
    • 0:t1t2的重合;
    • - *
    • -1:t1t2的右侧;
    • - *
    - * - * @param bound 边界 - * @return 位置 - */ - @Override - public int compareTo(final Bound 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 negate() { - return this; - } - - /** - * 将当前实例转为一个区间 - * - * @return 区间 - */ - @Override - public BoundedRange toRange() { - return BoundedRange.all(); - } - - /** - * 获得当前实例对应的{@code { x | x >= xxx}}格式的不等式字符串 - * - * @return 字符串 - */ - @Override - public String toString() { - return "{x | x > -\u221e}"; - } - - } - - /** - * 无限大的右边界 - * - * @param 边界值类型 - */ - class NoneUpperBound> implements Bound { - - 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; - } - - /** - *

    比较另一边界与当前边界在坐标轴上位置的先后顺序。
    - * 若令当前边界为t1,另一边界为t2,则有 - *

      - *
    • -1:t1t2的左侧;
    • - *
    • 0:t1t2的重合;
    • - *
    • -1:t1t2的右侧;
    • - *
    - * - * @param bound 边界 - * @return 位置 - */ - @Override - public int compareTo(final Bound 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 negate() { - return this; - } - - /** - * 将当前实例转为一个区间 - * - * @return 区间 - */ - @Override - public BoundedRange toRange() { - return BoundedRange.all(); - } - - } - } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/range/BoundType.java b/hutool-core/src/main/java/cn/hutool/core/lang/range/BoundType.java index 55e43071f..ce22ec4af 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/range/BoundType.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/range/BoundType.java @@ -1,7 +1,7 @@ package cn.hutool.core.lang.range; /** - * 边界类型 + * 边界类型枚举 * * @author huangchengxing * @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) { this.symbol = symbol; @@ -85,7 +88,7 @@ public enum BoundType { * @param boundType 另一边界类型 * @return 是否 */ - public boolean isDislocated(BoundType boundType) { + public boolean isDislocated(final BoundType boundType) { return code * boundType.code < 0; } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/range/BoundedRange.java b/hutool-core/src/main/java/cn/hutool/core/lang/range/BoundedRange.java index bed3e30c4..5992c7754 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/range/BoundedRange.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/range/BoundedRange.java @@ -1,5 +1,6 @@ package cn.hutool.core.lang.range; +import cn.hutool.core.comparator.CompareUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Opt; @@ -10,8 +11,8 @@ import java.util.function.Predicate; *

    参考GuavaRange实现,用于描述作为上下界的两个{@link Bound}实例围成的一段区间。
    * 作为{@link Predicate}使用时,可检验指定值是否在区间中,即指定值是否同时满足上下界的{@link Bound#test}方法。 * - *

    区间的类型

    - *

    支持通过工厂方法创建下述几种类型的区间 + *

    区间的类型,支持通过工厂方法创建下述几种类型的区间:

    + * *
    区间 数学定义 工厂方法 *
    {@code (a, b)} {@code {x | a < x < b}} {@link #open} *
    {@code [a, b]} {@code {x | a <= x <= b}}{@link #close} @@ -24,7 +25,7 @@ import java.util.function.Predicate; *
    {@code (-∞, +∞)}{@code {x}} {@link #all} *
    * - *

    空区间

    + *

    空区间

    *

    根据数学定义,当区间中无任何实数时,认为该区间代表的集合为空集, * 用户可通过{@link #isEmpty}确认当前实例是否为空区间。
    * 若实例上界a,下界为b,则当实例满足下述任意条件时,认为其为一个空区间: @@ -49,7 +50,7 @@ public class BoundedRange> implements Predicate< /** * 双向无界的区间 */ - @SuppressWarnings("rawtypes") + @SuppressWarnings({"rawtypes", "unchecked"}) private static final BoundedRange ALL = new BoundedRange(Bound.noneLowerBound(), Bound.noneUpperBound()); /** @@ -80,15 +81,15 @@ public class BoundedRange> implements Predicate< * @param 边界值类型 * @return 区间 * @throws IllegalArgumentException 当创建的区间表示的集合为空时抛出 - * @throws NullPointerException 上界或下界为{@code null}时抛出 + * @throws NullPointerException 上界或下界为{@code null}时抛出 */ static > BoundedRange close(final T lowerBound, final T upperBound) { Objects.requireNonNull(lowerBound); Objects.requireNonNull(upperBound); return checkEmpty( - new BoundedRange<>( - Bound.atLeast(lowerBound), Bound.atMost(upperBound) - ) + new BoundedRange<>( + Bound.atLeast(lowerBound), Bound.atMost(upperBound) + ) ); } @@ -100,13 +101,13 @@ public class BoundedRange> implements Predicate< * @param 边界值类型 * @return 区间 * @throws IllegalArgumentException 当创建的区间表示的集合为空时抛出 - * @throws NullPointerException 上界或下界为{@code null}时抛出 + * @throws NullPointerException 上界或下界为{@code null}时抛出 */ static > BoundedRange open(final T lowerBound, final T upperBound) { Objects.requireNonNull(lowerBound); Objects.requireNonNull(upperBound); 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> implements Predicate< * @param 边界值类型 * @return 区间 * @throws IllegalArgumentException 当创建的区间表示的集合为空时抛出 - * @throws NullPointerException 上界或下界为{@code null}时抛出 + * @throws NullPointerException 上界或下界为{@code null}时抛出 */ static > BoundedRange closeOpen(final T lowerBound, final T upperBound) { Objects.requireNonNull(lowerBound); Objects.requireNonNull(upperBound); return checkEmpty( - new BoundedRange<>( - Bound.atLeast(lowerBound), - Bound.lessThan(upperBound) - ) + new BoundedRange<>( + Bound.atLeast(lowerBound), + Bound.lessThan(upperBound) + ) ); } @@ -139,16 +140,16 @@ public class BoundedRange> implements Predicate< * @param 边界值类型 * @return 区间 * @throws IllegalArgumentException 当创建的区间表示的集合为空时抛出 - * @throws NullPointerException 上界或下界为{@code null}时抛出 + * @throws NullPointerException 上界或下界为{@code null}时抛出 */ static > BoundedRange openClose(final T lowerBound, final T upperBound) { Objects.requireNonNull(lowerBound); Objects.requireNonNull(upperBound); return checkEmpty( - new BoundedRange<>( - Bound.greaterThan(lowerBound), - Bound.atMost(upperBound) - ) + new BoundedRange<>( + Bound.greaterThan(lowerBound), + Bound.atMost(upperBound) + ) ); } @@ -287,19 +288,19 @@ public class BoundedRange> implements Predicate< * @return 是否 */ public boolean isEmpty() { - Bound low = getLowerBound(); - Bound up = getUpperBound(); - if (low instanceof Bound.NoneLowerBound || up instanceof Bound.NoneUpperBound) { + final Bound low = getLowerBound(); + final Bound up = getUpperBound(); + if (low instanceof NoneLowerBound || up instanceof NoneUpperBound) { return false; } - int compareValue = low.getValue().compareTo(up.getValue()); + final int compareValue = low.getValue().compareTo(up.getValue()); if (compareValue < 0) { return false; } // 上界小于下界时为空 return compareValue > 0 - // 上下界的边界值相等,且不为退化区间是为空 - || !(low.getType().isClose() && up.getType().isClose()); + // 上下界的边界值相等,且不为退化区间是为空 + || !(low.getType().isClose() && up.getType().isClose()); } /** @@ -326,7 +327,7 @@ public class BoundedRange> implements Predicate< if (o == null || getClass() != o.getClass()) { return false; } - final BoundedRange that = (BoundedRange)o; + final BoundedRange that = (BoundedRange) o; return lowerBound.equals(that.lowerBound) && upperBound.equals(that.upperBound); } @@ -352,7 +353,7 @@ public class BoundedRange> implements Predicate< */ public boolean isSuperset(final BoundedRange other) { return getLowerBound().compareTo(other.getLowerBound()) <= 0 - && getUpperBound().compareTo(other.getUpperBound()) >= 0; + && getUpperBound().compareTo(other.getUpperBound()) >= 0; } /** @@ -363,7 +364,7 @@ public class BoundedRange> implements Predicate< */ public boolean isProperSuperset(final BoundedRange other) { return getLowerBound().compareTo(other.getLowerBound()) < 0 - && getUpperBound().compareTo(other.getUpperBound()) > 0; + && getUpperBound().compareTo(other.getUpperBound()) > 0; } /** @@ -374,7 +375,7 @@ public class BoundedRange> implements Predicate< */ public boolean isSubset(final BoundedRange other) { return getLowerBound().compareTo(other.getLowerBound()) >= 0 - && getUpperBound().compareTo(other.getUpperBound()) <= 0; + && getUpperBound().compareTo(other.getUpperBound()) <= 0; } /** @@ -385,7 +386,7 @@ public class BoundedRange> implements Predicate< */ public boolean isProperSubset(final BoundedRange other) { return getLowerBound().compareTo(other.getLowerBound()) > 0 - && getUpperBound().compareTo(other.getUpperBound()) < 0; + && getUpperBound().compareTo(other.getUpperBound()) < 0; } /** @@ -396,7 +397,7 @@ public class BoundedRange> implements Predicate< */ public boolean isDisjoint(final BoundedRange other) { return getLowerBound().compareTo(other.getUpperBound()) > 0 - || getUpperBound().compareTo(other.getLowerBound()) < 0; + || getUpperBound().compareTo(other.getLowerBound()) < 0; } /** @@ -418,7 +419,7 @@ public class BoundedRange> implements Predicate< public boolean isEquals(final BoundedRange other) { Objects.requireNonNull(other); return other.getLowerBound().compareTo(getLowerBound()) == 0 - && other.getUpperBound().compareTo(getUpperBound()) == 0; + && other.getUpperBound().compareTo(getUpperBound()) == 0; } /** @@ -430,8 +431,8 @@ public class BoundedRange> implements Predicate< @Override public boolean test(final T value) { return getLowerBound() - .and(getUpperBound()) - .test(value); + .and(getUpperBound()) + .test(value); } // endregion @@ -450,8 +451,8 @@ public class BoundedRange> implements Predicate< return this; } return new BoundedRange<>( - getMin(getLowerBound(), other.getLowerBound()), - getMax(getUpperBound(), other.getUpperBound()) + CompareUtil.min(getLowerBound(), other.getLowerBound()), + CompareUtil.max(getUpperBound(), other.getUpperBound()) ); } @@ -464,8 +465,8 @@ public class BoundedRange> implements Predicate< public BoundedRange span(final BoundedRange other) { Objects.requireNonNull(other); return new BoundedRange<>( - getMin(getLowerBound(), other.getLowerBound()), - getMax(getUpperBound(), other.getUpperBound()) + CompareUtil.min(getLowerBound(), other.getLowerBound()), + CompareUtil.max(getUpperBound(), other.getUpperBound()) ); } @@ -481,8 +482,8 @@ public class BoundedRange> implements Predicate< return null; } return new BoundedRange<>( - getMin(getUpperBound(), other.getUpperBound()).negate(), - getMax(getLowerBound(), other.getLowerBound()).negate() + CompareUtil.min(getUpperBound(), other.getUpperBound()).negate(), + CompareUtil.max(getLowerBound(), other.getLowerBound()).negate() ); } @@ -498,8 +499,8 @@ public class BoundedRange> implements Predicate< return null; } return new BoundedRange<>( - getMax(getLowerBound(), other.getLowerBound()), - getMin(getUpperBound(), other.getUpperBound()) + CompareUtil.min(getLowerBound(), other.getLowerBound()), + CompareUtil.max(getUpperBound(), other.getUpperBound()) ); } @@ -511,9 +512,9 @@ public class BoundedRange> implements Predicate< */ public BoundedRange subGreatThan(final T min) { return Opt.ofNullable(min) - .filter(this) - .map(t -> new BoundedRange<>(Bound.greaterThan(t), getUpperBound())) - .orElse(this); + .filter(this) + .map(t -> new BoundedRange<>(Bound.greaterThan(t), getUpperBound())) + .orElse(this); } /** @@ -524,9 +525,9 @@ public class BoundedRange> implements Predicate< */ public BoundedRange subAtLeast(final T min) { return Opt.ofNullable(min) - .filter(this) - .map(t -> new BoundedRange<>(Bound.atLeast(t), getUpperBound())) - .orElse(this); + .filter(this) + .map(t -> new BoundedRange<>(Bound.atLeast(t), getUpperBound())) + .orElse(this); } /** @@ -537,9 +538,9 @@ public class BoundedRange> implements Predicate< */ public BoundedRange subLessThan(final T max) { return Opt.ofNullable(max) - .filter(this) - .map(t -> new BoundedRange<>(getLowerBound(), Bound.lessThan(max))) - .orElse(this); + .filter(this) + .map(t -> new BoundedRange<>(getLowerBound(), Bound.lessThan(max))) + .orElse(this); } /** @@ -550,22 +551,14 @@ public class BoundedRange> implements Predicate< */ public BoundedRange subAtMost(final T max) { return Opt.ofNullable(max) - .filter(this) - .map(t -> new BoundedRange<>(getLowerBound(), Bound.atMost(max))) - .orElse(this); + .filter(this) + .map(t -> new BoundedRange<>(getLowerBound(), Bound.atMost(max))) + .orElse(this); } // endregion - private static > Bound getMin(Bound b1, Bound b2) { - return b1.compareTo(b2) <= 0 ? b1 : b2; - } - - private static > Bound getMax(Bound b1, Bound b2) { - return b1.compareTo(b2) >= 0 ? b1 : b2; - } - - private static > BoundedRange checkEmpty(BoundedRange range) { + private static > BoundedRange checkEmpty(final BoundedRange range) { Assert.isFalse(range.isEmpty(), "{} is a empty range", range); return range; } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/range/NoneLowerBound.java b/hutool-core/src/main/java/cn/hutool/core/lang/range/NoneLowerBound.java new file mode 100644 index 000000000..b9d69d397 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/range/NoneLowerBound.java @@ -0,0 +1,108 @@ +package cn.hutool.core.lang.range; + +/** + * 无限小的左边界 + * + * @param 边界值类型 + * @author huangchengxing + * @since 6.0.0 + */ +class NoneLowerBound> implements Bound { + /** + * 无限小的左边界单例 + */ + @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; + } + + /** + *

    比较另一边界与当前边界在坐标轴上位置的先后顺序。
    + * 若令当前边界为t1,另一边界为t2,则有 + *

      + *
    • -1:t1t2的左侧;
    • + *
    • 0:t1t2的重合;
    • + *
    • -1:t1t2的右侧;
    • + *
    + * + * @param bound 边界 + * @return 位置 + */ + @Override + public int compareTo(final Bound 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 negate() { + return this; + } + + /** + * 将当前实例转为一个区间 + * + * @return 区间 + */ + @Override + public BoundedRange toRange() { + return BoundedRange.all(); + } + + /** + * 获得当前实例对应的{@code { x | x >= xxx}}格式的不等式字符串 + * + * @return 字符串 + */ + @Override + public String toString() { + return "{x | x > -\u221e}"; + } + +} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/range/NoneUpperBound.java b/hutool-core/src/main/java/cn/hutool/core/lang/range/NoneUpperBound.java new file mode 100644 index 000000000..8112dbdd1 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/range/NoneUpperBound.java @@ -0,0 +1,106 @@ +package cn.hutool.core.lang.range; + +/** + * 无限大的右边界 + * + * @param 边界值类型 + */ +class NoneUpperBound> implements Bound { + /** + * 无限大的右边界 + */ + @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; + } + + /** + *

    比较另一边界与当前边界在坐标轴上位置的先后顺序。
    + * 若令当前边界为t1,另一边界为t2,则有 + *

      + *
    • -1:t1t2的左侧;
    • + *
    • 0:t1t2的重合;
    • + *
    • -1:t1t2的右侧;
    • + *
    + * + * @param bound 边界 + * @return 位置 + */ + @Override + public int compareTo(final Bound 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 negate() { + return this; + } + + /** + * 将当前实例转为一个区间 + * + * @return 区间 + */ + @Override + public BoundedRange toRange() { + return BoundedRange.all(); + } + +} 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/Range.java similarity index 98% rename from hutool-core/src/main/java/cn/hutool/core/lang/Range.java rename to hutool-core/src/main/java/cn/hutool/core/lang/range/Range.java index 99732147f..f53fd91e1 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/Range.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/range/Range.java @@ -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 java.io.Serializable; diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/range/package-info.java b/hutool-core/src/main/java/cn/hutool/core/lang/range/package-info.java new file mode 100644 index 000000000..5c75bb8ae --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/range/package-info.java @@ -0,0 +1,10 @@ +/** + * 提供区间和边界封装,主要包括: + *
      + *
    • {@link cn.hutool.core.lang.range.Bound}: 提供边界的抽象表示,包括边界范围、开闭区间等。
    • + *
    • {@link cn.hutool.core.lang.range.Range}: 提供可迭代的区间。
    • + *
    + * + * @author huangchengxing, looly + */ +package cn.hutool.core.lang.range; diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java index 530656cd4..77332059d 100755 --- a/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ArrayUtil.java @@ -1394,7 +1394,8 @@ public class ArrayUtil extends PrimitiveArrayUtil { * @return 最小值 * @since 3.0.9 */ - public static > T min(final T[] numberArray) { + @SafeVarargs + public static > T min(final T... numberArray) { return min(numberArray, null); } @@ -1428,7 +1429,8 @@ public class ArrayUtil extends PrimitiveArrayUtil { * @return 最大值 * @since 3.0.9 */ - public static > T max(final T[] numberArray) { + @SafeVarargs + public static > T max(final T... numberArray) { return max(numberArray, null); } 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 ba75a0224..791dc890f 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 @@ -4,6 +4,7 @@ import cn.hutool.core.date.DateField; import cn.hutool.core.date.DateRange; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.range.Range; import cn.hutool.core.text.StrUtil; import org.junit.Assert; import org.junit.Test;