mirror of
https://gitee.com/dromara/hutool.git
synced 2026-02-09 09:16:26 +08:00
add test
This commit is contained in:
@@ -1015,7 +1015,7 @@ public class ArrayUtil extends PrimitiveArrayUtil {
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region ----- filter
|
||||
// region ----- edit and filter
|
||||
|
||||
/**
|
||||
* 对每个数组元素执行指定操作,返回操作后的元素<br>
|
||||
|
||||
@@ -22,8 +22,9 @@ import cn.hutool.v7.core.util.ObjUtil;
|
||||
import cn.hutool.v7.core.util.RandomUtil;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
/**
|
||||
* 原始类型数组工具类,原始类型数据包括:
|
||||
@@ -1737,6 +1738,7 @@ public class PrimitiveArrayUtil {
|
||||
|
||||
return result;
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region ----- removeEle
|
||||
|
||||
@@ -1861,6 +1863,568 @@ public class PrimitiveArrayUtil {
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region ----- removeElements
|
||||
|
||||
/**
|
||||
* 从字符数组中移除指定的多个字符
|
||||
*
|
||||
* @param array 原始字符数组
|
||||
* @param elements 要移除的字符数组
|
||||
* @return 移除指定字符后的新数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static char[] removeElements(final char[] array, final char... elements) {
|
||||
if (isEmpty(array) || isEmpty(elements)) {
|
||||
return array;
|
||||
}
|
||||
|
||||
return filter(array, t -> !ArrayUtil.contains(elements, t));
|
||||
}
|
||||
|
||||
// ==================== byte 类型 ====================
|
||||
|
||||
/**
|
||||
* 从byte数组中移除指定的多个byte元素
|
||||
*
|
||||
* @param array 原始byte数组
|
||||
* @param elements 要移除的byte数组
|
||||
* @return 移除指定元素后的新数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static byte[] removeElements(final byte[] array, final byte... elements) {
|
||||
if (isEmpty(array) || isEmpty(elements)) {
|
||||
return array;
|
||||
}
|
||||
|
||||
return filter(array, t -> !contains(elements, t));
|
||||
}
|
||||
|
||||
// ==================== short 类型 ====================
|
||||
|
||||
/**
|
||||
* 从short数组中移除指定的多个short元素
|
||||
*
|
||||
* @param array 原始short数组
|
||||
* @param elements 要移除的short数组
|
||||
* @return 移除指定元素后的新数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static short[] removeElements(final short[] array, final short... elements) {
|
||||
if (isEmpty(array) || isEmpty(elements)) {
|
||||
return array;
|
||||
}
|
||||
|
||||
return filter(array, t -> !contains(elements, t));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从int数组中移除指定的多个int元素
|
||||
*
|
||||
* @param array 原始int数组
|
||||
* @param elements 要移除的int数组
|
||||
* @return 移除指定元素后的新数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static int[] removeElements(final int[] array, final int... elements) {
|
||||
if (isEmpty(array) || isEmpty(elements)) {
|
||||
return array;
|
||||
}
|
||||
|
||||
return filter(array, t -> !contains(elements, t));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从long数组中移除指定的多个long元素
|
||||
*
|
||||
* @param array 原始long数组
|
||||
* @param elements 要移除的long数组
|
||||
* @return 移除指定元素后的新数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static long[] removeElements(final long[] array, final long... elements) {
|
||||
if (isEmpty(array) || isEmpty(elements)) {
|
||||
return array;
|
||||
}
|
||||
|
||||
return filter(array, t -> !contains(elements, t));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从float数组中移除指定的多个float元素
|
||||
*
|
||||
* @param array 原始float数组
|
||||
* @param elements 要移除的float数组
|
||||
* @return 移除指定元素后的新数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static float[] removeElements(final float[] array, final float... elements) {
|
||||
if (isEmpty(array) || isEmpty(elements)) {
|
||||
return array;
|
||||
}
|
||||
|
||||
return filter(array, t -> !contains(elements, t));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从double数组中移除指定的多个double元素
|
||||
*
|
||||
* @param array 原始double数组
|
||||
* @param elements 要移除的double数组
|
||||
* @return 移除指定元素后的新数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static double[] removeElements(final double[] array, final double... elements) {
|
||||
if (isEmpty(array) || isEmpty(elements)) {
|
||||
return array;
|
||||
}
|
||||
|
||||
return filter(array, t -> !contains(elements, t));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从boolean数组中移除指定的多个boolean元素
|
||||
*
|
||||
* @param array 原始boolean数组
|
||||
* @param elements 要移除的boolean数组
|
||||
* @return 移除指定元素后的新数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static boolean[] removeElements(final boolean[] array, final boolean... elements) {
|
||||
if (isEmpty(array) || isEmpty(elements)) {
|
||||
return array;
|
||||
}
|
||||
|
||||
return filter(array, t -> !contains(elements, t));
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region ----- edit and filter
|
||||
|
||||
/**
|
||||
* 对每个数组元素执行指定操作,返回操作后的元素<br>
|
||||
* 这个Editor实现可以实现以下功能:
|
||||
* <ol>
|
||||
* <li>过滤出需要的对象,如果返回{@code null}则抛弃这个元素对象</li>
|
||||
* <li>修改元素对象,返回修改后的对象</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param array 数组
|
||||
* @param editor 编辑器接口,为 {@code null}则返回原数组
|
||||
* @return 编辑后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static char[] edit(final char[] array, final UnaryOperator<Character> editor) {
|
||||
if (null == array || null == editor) {
|
||||
return array;
|
||||
}
|
||||
|
||||
final List<Character> resultList = new ArrayList<>(array.length);
|
||||
Character modified;
|
||||
for (final Character t : array) {
|
||||
modified = editor.apply(t);
|
||||
if (null != modified) {
|
||||
resultList.add(modified);
|
||||
}
|
||||
}
|
||||
|
||||
// 将List转换为char[]数组
|
||||
final int size = resultList.size();
|
||||
final char[] resultArray = new char[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
resultArray[i] = resultList.get(i);
|
||||
}
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对每个byte数组元素执行指定操作,返回操作后的元素<br>
|
||||
* 这个Editor实现可以实现以下功能:
|
||||
* <ol>
|
||||
* <li>过滤出需要的对象,如果返回{@code null}则抛弃这个元素对象</li>
|
||||
* <li>修改元素对象,返回修改后的对象</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param array 数组
|
||||
* @param editor 编辑器接口,为 {@code null}则返回原数组
|
||||
* @return 编辑后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static byte[] edit(final byte[] array, final UnaryOperator<Byte> editor) {
|
||||
if (null == array || null == editor) {
|
||||
return array;
|
||||
}
|
||||
|
||||
final List<Byte> resultList = new ArrayList<>(array.length);
|
||||
Byte modified;
|
||||
for (final Byte t : array) {
|
||||
modified = editor.apply(t);
|
||||
if (null != modified) {
|
||||
resultList.add(modified);
|
||||
}
|
||||
}
|
||||
|
||||
// 将List转换为byte[]数组
|
||||
final int size = resultList.size();
|
||||
final byte[] resultArray = new byte[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
resultArray[i] = resultList.get(i);
|
||||
}
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对每个short数组元素执行指定操作,返回操作后的元素<br>
|
||||
* 这个Editor实现可以实现以下功能:
|
||||
* <ol>
|
||||
* <li>过滤出需要的对象,如果返回{@code null}则抛弃这个元素对象</li>
|
||||
* <li>修改元素对象,返回修改后的对象</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param array 数组
|
||||
* @param editor 编辑器接口,为 {@code null}则返回原数组
|
||||
* @return 编辑后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static short[] edit(final short[] array, final UnaryOperator<Short> editor) {
|
||||
if (null == array || null == editor) {
|
||||
return array;
|
||||
}
|
||||
|
||||
final List<Short> resultList = new ArrayList<>(array.length);
|
||||
Short modified;
|
||||
for (final Short t : array) {
|
||||
modified = editor.apply(t);
|
||||
if (null != modified) {
|
||||
resultList.add(modified);
|
||||
}
|
||||
}
|
||||
|
||||
// 将List转换为short[]数组
|
||||
final int size = resultList.size();
|
||||
final short[] resultArray = new short[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
resultArray[i] = resultList.get(i);
|
||||
}
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对每个int数组元素执行指定操作,返回操作后的元素<br>
|
||||
* 这个Editor实现可以实现以下功能:
|
||||
* <ol>
|
||||
* <li>过滤出需要的对象,如果返回{@code null}则抛弃这个元素对象</li>
|
||||
* <li>修改元素对象,返回修改后的对象</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param array 数组
|
||||
* @param editor 编辑器接口,为 {@code null}则返回原数组
|
||||
* @return 编辑后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static int[] edit(final int[] array, final UnaryOperator<Integer> editor) {
|
||||
if (null == array || null == editor) {
|
||||
return array;
|
||||
}
|
||||
|
||||
final List<Integer> resultList = new ArrayList<>(array.length);
|
||||
Integer modified;
|
||||
for (final Integer t : array) {
|
||||
modified = editor.apply(t);
|
||||
if (null != modified) {
|
||||
resultList.add(modified);
|
||||
}
|
||||
}
|
||||
|
||||
// 将List转换为int[]数组
|
||||
final int size = resultList.size();
|
||||
final int[] resultArray = new int[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
resultArray[i] = resultList.get(i);
|
||||
}
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对每个long数组元素执行指定操作,返回操作后的元素<br>
|
||||
* 这个Editor实现可以实现以下功能:
|
||||
* <ol>
|
||||
* <li>过滤出需要的对象,如果返回{@code null}则抛弃这个元素对象</li>
|
||||
* <li>修改元素对象,返回修改后的对象</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param array 数组
|
||||
* @param editor 编辑器接口,为 {@code null}则返回原数组
|
||||
* @return 编辑后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static long[] edit(final long[] array, final UnaryOperator<Long> editor) {
|
||||
if (null == array || null == editor) {
|
||||
return array;
|
||||
}
|
||||
|
||||
final List<Long> resultList = new ArrayList<>(array.length);
|
||||
Long modified;
|
||||
for (final Long t : array) {
|
||||
modified = editor.apply(t);
|
||||
if (null != modified) {
|
||||
resultList.add(modified);
|
||||
}
|
||||
}
|
||||
|
||||
// 将List转换为long[]数组
|
||||
final int size = resultList.size();
|
||||
final long[] resultArray = new long[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
resultArray[i] = resultList.get(i);
|
||||
}
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对每个float数组元素执行指定操作,返回操作后的元素<br>
|
||||
* 这个Editor实现可以实现以下功能:
|
||||
* <ol>
|
||||
* <li>过滤出需要的对象,如果返回{@code null}则抛弃这个元素对象</li>
|
||||
* <li>修改元素对象,返回修改后的对象</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param array 数组
|
||||
* @param editor 编辑器接口,为 {@code null}则返回原数组
|
||||
* @return 编辑后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static float[] edit(final float[] array, final UnaryOperator<Float> editor) {
|
||||
if (null == array || null == editor) {
|
||||
return array;
|
||||
}
|
||||
|
||||
final List<Float> resultList = new ArrayList<>(array.length);
|
||||
Float modified;
|
||||
for (final Float t : array) {
|
||||
modified = editor.apply(t);
|
||||
if (null != modified) {
|
||||
resultList.add(modified);
|
||||
}
|
||||
}
|
||||
|
||||
// 将List转换为float[]数组
|
||||
final int size = resultList.size();
|
||||
final float[] resultArray = new float[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
resultArray[i] = resultList.get(i);
|
||||
}
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对每个double数组元素执行指定操作,返回操作后的元素<br>
|
||||
* 这个Editor实现可以实现以下功能:
|
||||
* <ol>
|
||||
* <li>过滤出需要的对象,如果返回{@code null}则抛弃这个元素对象</li>
|
||||
* <li>修改元素对象,返回修改后的对象</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param array 数组
|
||||
* @param editor 编辑器接口,为 {@code null}则返回原数组
|
||||
* @return 编辑后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static double[] edit(final double[] array, final UnaryOperator<Double> editor) {
|
||||
if (null == array || null == editor) {
|
||||
return array;
|
||||
}
|
||||
|
||||
final List<Double> resultList = new ArrayList<>(array.length);
|
||||
Double modified;
|
||||
for (final Double t : array) {
|
||||
modified = editor.apply(t);
|
||||
if (null != modified) {
|
||||
resultList.add(modified);
|
||||
}
|
||||
}
|
||||
|
||||
// 将List转换为double[]数组
|
||||
final int size = resultList.size();
|
||||
final double[] resultArray = new double[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
resultArray[i] = resultList.get(i);
|
||||
}
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对每个boolean数组元素执行指定操作,返回操作后的元素<br>
|
||||
* 这个Editor实现可以实现以下功能:
|
||||
* <ol>
|
||||
* <li>过滤出需要的对象,如果返回{@code null}则抛弃这个元素对象</li>
|
||||
* <li>修改元素对象,返回修改后的对象</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param array 数组
|
||||
* @param editor 编辑器接口,为 {@code null}则返回原数组
|
||||
* @return 编辑后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static boolean[] edit(final boolean[] array, final UnaryOperator<Boolean> editor) {
|
||||
if (null == array || null == editor) {
|
||||
return array;
|
||||
}
|
||||
|
||||
final List<Boolean> resultList = new ArrayList<>(array.length);
|
||||
Boolean modified;
|
||||
for (final Boolean t : array) {
|
||||
modified = editor.apply(t);
|
||||
if (null != modified) {
|
||||
resultList.add(modified);
|
||||
}
|
||||
}
|
||||
|
||||
// 将List转换为boolean[]数组
|
||||
final int size = resultList.size();
|
||||
final boolean[] resultArray = new boolean[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
resultArray[i] = resultList.get(i);
|
||||
}
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤数组元素<br>
|
||||
* 保留 {@link Predicate#test(Object)}为{@code true}的元素
|
||||
*
|
||||
* @param array 数组
|
||||
* @param predicate 过滤器接口,用于定义过滤规则,为{@code null}则返回原数组
|
||||
* @return 过滤后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static char[] filter(final char[] array, final Predicate<Character> predicate) {
|
||||
if (null == array || null == predicate) {
|
||||
return array;
|
||||
}
|
||||
return edit(array, t -> predicate.test(t) ? t : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤byte数组元素<br>
|
||||
* 保留 {@link Predicate#test(Object)}为{@code true}的元素
|
||||
*
|
||||
* @param array 数组
|
||||
* @param predicate 过滤器接口,用于定义过滤规则,为{@code null}则返回原数组
|
||||
* @return 过滤后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static byte[] filter(final byte[] array, final Predicate<Byte> predicate) {
|
||||
if (null == array || null == predicate) {
|
||||
return array;
|
||||
}
|
||||
return edit(array, t -> predicate.test(t) ? t : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤short数组元素<br>
|
||||
* 保留 {@link Predicate#test(Object)}为{@code true}的元素
|
||||
*
|
||||
* @param array 数组
|
||||
* @param predicate 过滤器接口,用于定义过滤规则,为{@code null}则返回原数组
|
||||
* @return 过滤后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static short[] filter(final short[] array, final Predicate<Short> predicate) {
|
||||
if (null == array || null == predicate) {
|
||||
return array;
|
||||
}
|
||||
return edit(array, t -> predicate.test(t) ? t : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤int数组元素<br>
|
||||
* 保留 {@link Predicate#test(Object)}为{@code true}的元素
|
||||
*
|
||||
* @param array 数组
|
||||
* @param predicate 过滤器接口,用于定义过滤规则,为{@code null}则返回原数组
|
||||
* @return 过滤后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static int[] filter(final int[] array, final Predicate<Integer> predicate) {
|
||||
if (null == array || null == predicate) {
|
||||
return array;
|
||||
}
|
||||
return edit(array, t -> predicate.test(t) ? t : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤long数组元素<br>
|
||||
* 保留 {@link Predicate#test(Object)}为{@code true}的元素
|
||||
*
|
||||
* @param array 数组
|
||||
* @param predicate 过滤器接口,用于定义过滤规则,为{@code null}则返回原数组
|
||||
* @return 过滤后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static long[] filter(final long[] array, final Predicate<Long> predicate) {
|
||||
if (null == array || null == predicate) {
|
||||
return array;
|
||||
}
|
||||
return edit(array, t -> predicate.test(t) ? t : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤float数组元素<br>
|
||||
* 保留 {@link Predicate#test(Object)}为{@code true}的元素
|
||||
*
|
||||
* @param array 数组
|
||||
* @param predicate 过滤器接口,用于定义过滤规则,为{@code null}则返回原数组
|
||||
* @return 过滤后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static float[] filter(final float[] array, final Predicate<Float> predicate) {
|
||||
if (null == array || null == predicate) {
|
||||
return array;
|
||||
}
|
||||
return edit(array, t -> predicate.test(t) ? t : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤double数组元素<br>
|
||||
* 保留 {@link Predicate#test(Object)}为{@code true}的元素
|
||||
*
|
||||
* @param array 数组
|
||||
* @param predicate 过滤器接口,用于定义过滤规则,为{@code null}则返回原数组
|
||||
* @return 过滤后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static double[] filter(final double[] array, final Predicate<Double> predicate) {
|
||||
if (null == array || null == predicate) {
|
||||
return array;
|
||||
}
|
||||
return edit(array, t -> predicate.test(t) ? t : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤boolean数组元素<br>
|
||||
* 保留 {@link Predicate#test(Object)}为{@code true}的元素
|
||||
*
|
||||
* @param array 数组
|
||||
* @param predicate 过滤器接口,用于定义过滤规则,为{@code null}则返回原数组
|
||||
* @return 过滤后的数组
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static boolean[] filter(final boolean[] array, final Predicate<Boolean> predicate) {
|
||||
if (null == array || null == predicate) {
|
||||
return array;
|
||||
}
|
||||
return edit(array, t -> predicate.test(t) ? t : null);
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region ----- reverse
|
||||
|
||||
/**
|
||||
@@ -2136,7 +2700,7 @@ public class PrimitiveArrayUtil {
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region ------------------------------------------- min and max
|
||||
// region ----- min and max
|
||||
|
||||
/**
|
||||
* 取最小值
|
||||
|
||||
@@ -512,6 +512,19 @@ public class Validator {
|
||||
return NumberUtil.isNumber(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助方法:检查字符串是否只包含数字
|
||||
*
|
||||
* @param str 字符串
|
||||
* @return 是否只包含数字
|
||||
*/
|
||||
public static boolean isNumeric(final String str) {
|
||||
if (StrUtil.isBlank( str)) {
|
||||
return false;
|
||||
}
|
||||
return isMatchRegex("\\d+", str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否包含数字
|
||||
*
|
||||
@@ -621,14 +634,15 @@ public class Validator {
|
||||
|
||||
/**
|
||||
* 验证是否为可用邮箱地址<br>
|
||||
* 邮箱地址限制长度为254个字符,参考:https://stackoverflow.com/questions/386294/what-is-the-maximum-length-of-a-valid-email-address/44317754
|
||||
* 邮箱地址限制长度为254个字符,参考:
|
||||
* <a href="https://stackoverflow.com/questions/386294/what-is-the-maximum-length-of-a-valid-email-address/44317754">what-is-the-maximum-length-of-a-valid-email-address</a>
|
||||
*
|
||||
* @param value 值
|
||||
* @return true为可用邮箱地址
|
||||
*/
|
||||
public static boolean isEmail(final CharSequence value) {
|
||||
final int codeLength = StrUtil.codeLength(value);
|
||||
if(codeLength < 1 || codeLength > 254){
|
||||
if (codeLength < 1 || codeLength > 254) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1056,9 +1070,9 @@ public class Validator {
|
||||
// final double doubleValue = value.doubleValue();
|
||||
// return (doubleValue >= min.doubleValue()) && (doubleValue <= max.doubleValue());
|
||||
// 通过 NumberUtil 转换为 BigDecimal,使用 BigDecimal 进行比较以保留精度
|
||||
BigDecimal valBd = NumberUtil.toBigDecimal(value);
|
||||
BigDecimal minBd = NumberUtil.toBigDecimal(min);
|
||||
BigDecimal maxBd = NumberUtil.toBigDecimal(max);
|
||||
final BigDecimal valBd = NumberUtil.toBigDecimal(value);
|
||||
final BigDecimal minBd = NumberUtil.toBigDecimal(min);
|
||||
final BigDecimal maxBd = NumberUtil.toBigDecimal(max);
|
||||
return valBd.compareTo(minBd) >= 0 && valBd.compareTo(maxBd) <= 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +128,19 @@ public class StrUtil extends CharSequenceUtil implements StrPool {
|
||||
|
||||
// region ----- str
|
||||
|
||||
/**
|
||||
* 将char[]转为String
|
||||
*
|
||||
* @param chars 字符数组
|
||||
* @return 字符串, 如果给定值为null,返回null
|
||||
*/
|
||||
public static String str(final char[] chars) {
|
||||
if (null == chars) {
|
||||
return null;
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对象转为字符串<br>
|
||||
*
|
||||
@@ -295,20 +308,21 @@ public class StrUtil extends CharSequenceUtil implements StrPool {
|
||||
* 该方法按Unicode code point进行反转,支持Unicode字符的正确反转
|
||||
* 确保复杂字符不会被拆分,如表情符号等多字节字符
|
||||
* </p>
|
||||
*
|
||||
* @param str 被反转的字符串
|
||||
* @return 反转后的字符串,如果输入为null则返回null
|
||||
* @since 5.8.43
|
||||
*/
|
||||
public static String reverseByCodePoint(String str) {
|
||||
public static String reverseByCodePoint(final String str) {
|
||||
if (null == str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//按Unicode code point方式进行反转处理
|
||||
StringBuilder result = new StringBuilder();
|
||||
final StringBuilder result = new StringBuilder();
|
||||
for (int i = str.length(); i > 0; ) {
|
||||
//获取指定位置前的code point
|
||||
int codePoint = str.codePointBefore(i);
|
||||
final int codePoint = str.codePointBefore(i);
|
||||
//根据code point的字符数量调整索引位置
|
||||
i -= Character.charCount(codePoint);
|
||||
//将code point追加到结果中
|
||||
|
||||
@@ -27,10 +27,12 @@ import java.util.concurrent.ThreadLocalRandom;
|
||||
*/
|
||||
public class RandomUtil {
|
||||
|
||||
// region ----- static Strings
|
||||
/**
|
||||
* 用于随机选的数字
|
||||
*/
|
||||
public static final String NUMBERS = "0123456789";
|
||||
|
||||
/**
|
||||
* 用于随机选的大写字符
|
||||
*/
|
||||
@@ -51,6 +53,35 @@ public class RandomUtil {
|
||||
* 用于随机选的字符和数字(包括大写和小写字母)
|
||||
*/
|
||||
public static final String LETTERS_NUMBERS = LETTERS + NUMBERS;
|
||||
// endregion
|
||||
|
||||
// region ----- static chars
|
||||
/**
|
||||
* 用于随机选的数字
|
||||
*/
|
||||
private static final char[] NUMBERS_CHARS = NUMBERS.toCharArray();
|
||||
|
||||
/**
|
||||
* 用于随机选的大写字符
|
||||
*/
|
||||
private static final char[] LETTERS_UPPER_CHARS = LETTERS_UPPER.toCharArray();
|
||||
/**
|
||||
* 用于随机选的小写字符
|
||||
*/
|
||||
private static final char[] LETTERS_LOWER_CHARS = LETTERS_LOWER.toCharArray();
|
||||
/**
|
||||
* 用于随机选的字符(包含大写和小写)
|
||||
*/
|
||||
private static final char[] LETTERS_CHARS = LETTERS.toCharArray();
|
||||
/**
|
||||
* 用于随机选的字符和数字(小写)
|
||||
*/
|
||||
private static final char[] LETTERS_NUMBERS_LOWER_CHARS = LETTERS_NUMBERS_LOWER.toCharArray();
|
||||
/**
|
||||
* 用于随机选的字符和数字(包括大写和小写字母)
|
||||
*/
|
||||
private static final char[] LETTERS_NUMBERS_CHARS = LETTERS_NUMBERS.toCharArray();
|
||||
// endregion
|
||||
|
||||
// region ----- get or create Random
|
||||
|
||||
@@ -274,7 +305,7 @@ public class RandomUtil {
|
||||
* @since 5.2.1
|
||||
*/
|
||||
public static int[] randomInts(final int length) {
|
||||
final int[] range = NumberUtil.range(length);
|
||||
final int[] range = NumberUtil.range(length - 1);
|
||||
for (int i = 0; i < length; i++) {
|
||||
final int random = randomInt(i, length);
|
||||
ArrayUtil.swap(range, i, random);
|
||||
@@ -648,7 +679,7 @@ public class RandomUtil {
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String randomLettersAndNumbers(final int length) {
|
||||
return randomString(LETTERS_NUMBERS, length);
|
||||
return randomString(LETTERS_NUMBERS_CHARS, length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -658,7 +689,7 @@ public class RandomUtil {
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String randomLettersAndNumbersLower(final int length) {
|
||||
return randomString(LETTERS_NUMBERS_LOWER, length);
|
||||
return randomString(LETTERS_NUMBERS_LOWER_CHARS, length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -669,34 +700,38 @@ public class RandomUtil {
|
||||
* @since 4.0.13
|
||||
*/
|
||||
public static String randomLettersAndNumbersUpper(final int length) {
|
||||
return randomString(LETTERS_NUMBERS_LOWER, length).toUpperCase();
|
||||
return randomString(LETTERS_NUMBERS_LOWER_CHARS, length).toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得一个随机的字符串(只包含数字和字母) 并排除指定字符串
|
||||
*
|
||||
* @param length 字符串的长度
|
||||
* @param elemData 要排除的字符串,如:去重容易混淆的字符串,oO0、lL1、q9Q、pP,区分大小写
|
||||
* @param elemData 要排除的字符串,如:去重容易混淆的字符串,oO0、lL1、q9Q、pP,<b>区分</b>大小写
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String randomLettersAndNumbersWithoutStr(final int length, final String elemData) {
|
||||
String baseStr = LETTERS_NUMBERS;
|
||||
baseStr = StrUtil.removeAll(baseStr, elemData.toCharArray());
|
||||
return randomString(baseStr, length);
|
||||
char[] baseChars = LETTERS_NUMBERS_CHARS;
|
||||
if(StrUtil.isNotBlank(elemData)){
|
||||
baseChars = ArrayUtil.removeElements(baseChars, elemData.toCharArray());
|
||||
}
|
||||
return randomString(baseChars, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得一个随机的字符串(只包含数字和小写字母) 并排除指定字符串
|
||||
*
|
||||
* @param length 字符串的长度
|
||||
* @param elemData 要排除的字符串,如:去重容易混淆的字符串,oO0、lL1、q9Q、pP,不区分大小写
|
||||
* @param elemData 要排除的字符串,如:去重容易混淆的字符串,oO0、lL1、q9Q、pP,<b>不区分</b>大小写
|
||||
* @return 随机字符串
|
||||
* @since 5.8.28
|
||||
*/
|
||||
public static String randomLettersAndNumbersLowerWithoutStr(final int length, final String elemData) {
|
||||
String baseStr = LETTERS_NUMBERS_LOWER;
|
||||
baseStr = StrUtil.removeAll(baseStr, elemData.toLowerCase().toCharArray());
|
||||
return randomString(baseStr, length);
|
||||
char[] baseChars = LETTERS_NUMBERS_LOWER_CHARS;
|
||||
if(StrUtil.isNotBlank(elemData)){
|
||||
baseChars = ArrayUtil.removeElements(baseChars, elemData.toLowerCase().toCharArray());
|
||||
}
|
||||
return randomString(baseChars, length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -706,7 +741,7 @@ public class RandomUtil {
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String randomNumbers(final int length) {
|
||||
return randomString(NUMBERS, length);
|
||||
return randomString(NUMBERS_CHARS, length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -716,7 +751,7 @@ public class RandomUtil {
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String randomLetters(final int length) {
|
||||
return randomString(LETTERS, length);
|
||||
return randomString(LETTERS_CHARS, length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -726,7 +761,7 @@ public class RandomUtil {
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String randomLettersLower(final int length) {
|
||||
return randomString(LETTERS_LOWER, length);
|
||||
return randomString(LETTERS_LOWER_CHARS, length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -736,7 +771,7 @@ public class RandomUtil {
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String randomLettersUpper(final int length) {
|
||||
return randomString(LETTERS_UPPER, length);
|
||||
return randomString(LETTERS_UPPER_CHARS, length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -746,21 +781,20 @@ public class RandomUtil {
|
||||
* @param length 字符串的长度
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String randomString(final String baseString, int length) {
|
||||
if (StrUtil.isEmpty(baseString)) {
|
||||
return StrUtil.EMPTY;
|
||||
}
|
||||
if (length < 1) {
|
||||
length = 1;
|
||||
}
|
||||
public static String randomString(final String baseString, final int length) {
|
||||
Assert.notEmpty(baseString, "Base string can not be empty !");
|
||||
return randomString(baseString.toCharArray(), length);
|
||||
}
|
||||
|
||||
final StringBuilder sb = new StringBuilder(length);
|
||||
final int baseLength = baseString.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
final int number = randomInt(baseLength);
|
||||
sb.append(baseString.charAt(number));
|
||||
}
|
||||
return sb.toString();
|
||||
/**
|
||||
* 获得一个随机的字符串
|
||||
*
|
||||
* @param baseString 随机字符选取的样本
|
||||
* @param length 字符串的长度
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String randomString(final char[] baseString, final int length) {
|
||||
return new String(randomChars(baseString, length));
|
||||
}
|
||||
// endregion
|
||||
|
||||
@@ -773,7 +807,7 @@ public class RandomUtil {
|
||||
* @since 3.1.2
|
||||
*/
|
||||
public static char randomNumber() {
|
||||
return randomChar(NUMBERS);
|
||||
return randomChar(NUMBERS_CHARS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -783,7 +817,7 @@ public class RandomUtil {
|
||||
* @since 3.1.2
|
||||
*/
|
||||
public static char randomChar() {
|
||||
return randomChar(LETTERS_NUMBERS_LOWER);
|
||||
return randomChar(LETTERS_NUMBERS_LOWER_CHARS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -796,6 +830,41 @@ public class RandomUtil {
|
||||
public static char randomChar(final String baseString) {
|
||||
return baseString.charAt(randomInt(baseString.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机字符
|
||||
*
|
||||
* @param baseChars 随机字符选取的样本chars
|
||||
* @return 随机字符
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public static char randomChar(final char[] baseChars) {
|
||||
return baseChars[randomInt(baseChars.length)];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得一个随机的字符串
|
||||
*
|
||||
* @param baseChars 随机字符选取的样本
|
||||
* @param length 字符串的长度
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static char[] randomChars(final char[] baseChars, final int length) {
|
||||
if(ArrayUtil.isEmpty(baseChars)){
|
||||
throw new IllegalArgumentException("baseChars can not be empty !");
|
||||
}
|
||||
Assert.isTrue(length >= 1, "Length can not less than 1 !");
|
||||
|
||||
// 预先将基础字符串转为字符数组,避免每次charAt调用
|
||||
final int baseLength = baseChars.length;
|
||||
final char[] result = new char[length];
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
result[i] = baseChars[randomInt(baseLength)];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region ----- weightRandom
|
||||
@@ -857,4 +926,4 @@ public class RandomUtil {
|
||||
return DateUtil.offset(baseDate, dateField, randomInt(min, max));
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Hutool Team.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.array;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
public class PrimitiveArrayUtilTest {
|
||||
/**
|
||||
* 测试当原始数组为null时的情况
|
||||
*/
|
||||
@Test
|
||||
public void testRemoveElementsWithNullArray() {
|
||||
final char[] result = PrimitiveArrayUtil.removeElements((char[]) null, 'a', 'b');
|
||||
assertNull(result, "当原始数组为null时,应返回null");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试当原始数组为空数组时的情况
|
||||
*/
|
||||
@Test
|
||||
public void testRemoveElementsWithEmptyArray() {
|
||||
final char[] original = {};
|
||||
final char[] elementsToRemove = {'a', 'b'};
|
||||
|
||||
final char[] result = PrimitiveArrayUtil.removeElements(original, elementsToRemove);
|
||||
|
||||
assertArrayEquals(original, result, "当原始数组为空数组时,应返回原数组");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试当要移除的元素数组为null时的情况
|
||||
*/
|
||||
@Test
|
||||
public void testRemoveElementsWithNullElements() {
|
||||
final char[] original = {'a', 'b', 'c'};
|
||||
final char[] result = PrimitiveArrayUtil.removeElements(original, (char[]) null);
|
||||
|
||||
assertArrayEquals(original, result, "当要移除的元素数组为null时,应返回原数组");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试当要移除的元素数组为空时的情况
|
||||
*/
|
||||
@Test
|
||||
public void testRemoveElementsWithEmptyElements() {
|
||||
final char[] original = {'a', 'b', 'c'};
|
||||
final char[] elementsToRemove = {};
|
||||
|
||||
final char[] result = PrimitiveArrayUtil.removeElements(original, elementsToRemove);
|
||||
|
||||
assertArrayEquals(original, result, "当要移除的元素数组为空时,应返回原数组");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试移除存在的字符元素
|
||||
*/
|
||||
@Test
|
||||
public void testRemoveElementsExistingChars() {
|
||||
final char[] original = {'a', 'b', 'c', 'd', 'e'};
|
||||
final char[] elementsToRemove = {'b', 'd'};
|
||||
final char[] expected = {'a', 'c', 'e'};
|
||||
|
||||
final char[] result = PrimitiveArrayUtil.removeElements(original, elementsToRemove);
|
||||
|
||||
assertArrayEquals(expected, result, "应正确移除指定的字符元素");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试移除不存在的字符元素
|
||||
*/
|
||||
@Test
|
||||
public void testRemoveElementsNonExistingChars() {
|
||||
final char[] original = {'a', 'b', 'c'};
|
||||
final char[] elementsToRemove = {'x', 'y'};
|
||||
final char[] expected = {'a', 'b', 'c'};
|
||||
|
||||
final char[] result = PrimitiveArrayUtil.removeElements(original, elementsToRemove);
|
||||
|
||||
assertArrayEquals(expected, result, "当要移除的字符不存在时,应返回原数组");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试移除所有元素的情况
|
||||
*/
|
||||
@Test
|
||||
public void testRemoveElementsAllChars() {
|
||||
final char[] original = {'a', 'b', 'c'};
|
||||
final char[] elementsToRemove = {'a', 'b', 'c'};
|
||||
final char[] expected = {};
|
||||
|
||||
final char[] result = PrimitiveArrayUtil.removeElements(original, elementsToRemove);
|
||||
|
||||
assertArrayEquals(expected, result, "当移除所有元素时,应返回空数组");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试包含重复字符的情况
|
||||
*/
|
||||
@Test
|
||||
public void testRemoveElementsWithDuplicates() {
|
||||
final char[] original = {'a', 'b', 'a', 'c', 'b', 'd'};
|
||||
final char[] elementsToRemove = {'a', 'b'};
|
||||
final char[] expected = {'c', 'd'};
|
||||
|
||||
final char[] result = PrimitiveArrayUtil.removeElements(original, elementsToRemove);
|
||||
|
||||
assertArrayEquals(expected, result, "应正确处理重复字符的移除");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试包含特殊字符的情况
|
||||
*/
|
||||
@Test
|
||||
public void testRemoveElementsWithSpecialChars() {
|
||||
final char[] original = {' ', 'a', '\n', 'b', '\t', 'c'};
|
||||
final char[] elementsToRemove = {' ', '\n'};
|
||||
final char[] expected = {'a', 'b', '\t', 'c'};
|
||||
|
||||
final char[] result = PrimitiveArrayUtil.removeElements(original, elementsToRemove);
|
||||
|
||||
assertArrayEquals(expected, result, "应正确处理特殊字符的移除");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试移除单个字符的情况
|
||||
*/
|
||||
@Test
|
||||
public void testRemoveElementsSingleChar() {
|
||||
final char[] original = {'a', 'b', 'c', 'd'};
|
||||
final char[] elementsToRemove = {'c'};
|
||||
final char[] expected = {'a', 'b', 'd'};
|
||||
|
||||
final char[] result = PrimitiveArrayUtil.removeElements(original, elementsToRemove);
|
||||
|
||||
assertArrayEquals(expected, result, "应正确移除单个字符");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试移除一个不存在的单个字符
|
||||
*/
|
||||
@Test
|
||||
public void testRemoveElementsSingleNonExistingChar() {
|
||||
final char[] original = {'a', 'b', 'c'};
|
||||
final char[] elementsToRemove = {'x'};
|
||||
final char[] expected = {'a', 'b', 'c'};
|
||||
|
||||
final char[] result = PrimitiveArrayUtil.removeElements(original, elementsToRemove);
|
||||
|
||||
assertArrayEquals(expected, result, "当移除不存在的单个字符时,应返回原数组");
|
||||
}
|
||||
}
|
||||
@@ -18,17 +18,15 @@ package cn.hutool.v7.core.util;
|
||||
|
||||
import cn.hutool.v7.core.collection.ListUtil;
|
||||
import cn.hutool.v7.core.convert.ConvertUtil;
|
||||
import cn.hutool.v7.core.lang.Console;
|
||||
import cn.hutool.v7.core.lang.Validator;
|
||||
import cn.hutool.v7.core.math.NumberUtil;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@@ -52,12 +50,6 @@ public class RandomUtilTest {
|
||||
assertTrue(randomDouble <= 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
public void randomBooleanTest() {
|
||||
Console.log(RandomUtil.randomBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void randomNumberTest() {
|
||||
final char c = RandomUtil.randomNumber();
|
||||
@@ -94,8 +86,8 @@ public class RandomUtilTest {
|
||||
|
||||
@Test
|
||||
public void randomStringOfLengthTest(){
|
||||
final String s = RandomUtil.randomString("123", -1);
|
||||
assertNotNull(s);
|
||||
assertThrows(IllegalArgumentException.class, () -> RandomUtil.randomString("123", 0));
|
||||
assertThrows(IllegalArgumentException.class, () -> RandomUtil.randomString("123", -1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -114,27 +106,17 @@ public class RandomUtilTest {
|
||||
// 测试生成长度为5的数字字符串
|
||||
final String result1 = RandomUtil.randomNumbers(5);
|
||||
assertEquals(5, result1.length(), "生成的字符串长度应该等于指定长度");
|
||||
assertTrue(isNumeric(result1), "生成的字符串应该只包含数字");
|
||||
assertTrue(Validator.isNumeric(result1), "生成的字符串应该只包含数字");
|
||||
|
||||
// 测试生成长度为10的数字字符串
|
||||
final String result2 = RandomUtil.randomNumbers(10);
|
||||
assertEquals(10, result2.length(), "生成的字符串长度应该等于指定长度");
|
||||
assertTrue(isNumeric(result2), "生成的字符串应该只包含数字");
|
||||
assertTrue(Validator.isNumeric(result2), "生成的字符串应该只包含数字");
|
||||
|
||||
// 测试生成长度为1的数字字符串
|
||||
final String result3 = RandomUtil.randomNumbers(1);
|
||||
assertEquals(1, result3.length(), "生成的字符串长度应该等于指定长度");
|
||||
assertTrue(isNumeric(result3), "生成的字符串应该只包含数字");
|
||||
|
||||
// 测试生成长度为0的数字字符串(会被调整为1)
|
||||
final String result4 = RandomUtil.randomNumbers(0);
|
||||
assertEquals(1, result4.length(), "当长度为0时,应生成长度为1的字符串");
|
||||
assertTrue(isNumeric(result4), "生成的字符串应该只包含数字");
|
||||
|
||||
// 测试生成长度为负数的数字字符串(会被调整为1)
|
||||
final String result5 = RandomUtil.randomNumbers(-5);
|
||||
assertEquals(1, result5.length(), "当长度为负数时,应生成长度为1的字符串");
|
||||
assertTrue(isNumeric(result5), "生成的字符串应该只包含数字");
|
||||
assertTrue(Validator.isNumeric(result3), "生成的字符串应该只包含数字");
|
||||
|
||||
// 验证多次生成的结果都不相同(概率性验证)
|
||||
final String result6 = RandomUtil.randomNumbers(8);
|
||||
@@ -142,19 +124,121 @@ public class RandomUtilTest {
|
||||
// 由于是随机生成,不能保证一定不同,但大部分情况下应该不同
|
||||
// 所以我们主要验证它们都符合预期格式
|
||||
assertEquals(8, result6.length(), "生成的字符串长度应该等于指定长度");
|
||||
assertTrue(isNumeric(result6), "生成的字符串应该只包含数字");
|
||||
assertTrue(Validator.isNumeric(result6), "生成的字符串应该只包含数字");
|
||||
assertEquals(8, result7.length(), "生成的字符串长度应该等于指定长度");
|
||||
assertTrue(isNumeric(result7), "生成的字符串应该只包含数字");
|
||||
assertTrue(Validator.isNumeric(result7), "生成的字符串应该只包含数字");
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助方法:检查字符串是否只包含数字
|
||||
* 测试 randomDouble(double limit, int scale, RoundingMode roundingMode) 方法正常功能
|
||||
* 验证生成的随机数在正确范围内,并且精度符合要求
|
||||
*/
|
||||
private boolean isNumeric(final String str) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return false;
|
||||
@Test
|
||||
public void testRandomDoubleWithScaleAndRoundingMode() {
|
||||
// 测试基本功能:生成0到10之间的随机数,保留2位小数,四舍五入
|
||||
final double result = RandomUtil.randomDouble(10.0, 2, RoundingMode.HALF_UP);
|
||||
|
||||
// 验证结果在[0, 10)范围内
|
||||
assertTrue(result >= 0.0 && result < 10.0,
|
||||
"随机数应该在[0, 10)范围内,实际值:" + result);
|
||||
|
||||
// 验证小数点后最多2位数字
|
||||
final String resultStr = String.valueOf(result);
|
||||
if (resultStr.contains(".")) {
|
||||
final int decimalPlaces = resultStr.length() - resultStr.indexOf('.') - 1;
|
||||
assertTrue(decimalPlaces <= 2,
|
||||
"小数位数应该不超过2位,实际:" + decimalPlaces);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试不同的舍入模式
|
||||
*/
|
||||
@Test
|
||||
public void testRandomDoubleWithDifferentRoundingModes() {
|
||||
final double limit = 5.0;
|
||||
|
||||
// 测试向上舍入
|
||||
final double upResult = RandomUtil.randomDouble(limit, 2, RoundingMode.UP);
|
||||
assertTrue(upResult >= 0.0 && upResult < limit,
|
||||
"UP模式下随机数应该在[0, 5)范围内");
|
||||
|
||||
// 测试向下舍入
|
||||
final double downResult = RandomUtil.randomDouble(limit, 2, RoundingMode.DOWN);
|
||||
assertTrue(downResult >= 0.0 && downResult < limit,
|
||||
"DOWN模式下随机数应该在[0, 5)范围内");
|
||||
|
||||
// 测试四舍五入
|
||||
final double halfUpResult = RandomUtil.randomDouble(limit, 2, RoundingMode.HALF_UP);
|
||||
assertTrue(halfUpResult >= 0.0 && halfUpResult < limit,
|
||||
"HALF_UP模式下随机数应该在[0, 5)范围内");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试精度为0的情况
|
||||
*/
|
||||
@Test
|
||||
public void testRandomDoubleWithZeroScale() {
|
||||
final double result = RandomUtil.randomDouble(10.0, 0, RoundingMode.HALF_UP);
|
||||
|
||||
// 验证结果在[0, 10)范围内
|
||||
assertTrue(result >= 0.0 && result < 10.0,
|
||||
"随机数应该在[0, 10)范围内");
|
||||
|
||||
// 验证没有小数部分(整数)
|
||||
assertEquals(Math.floor(result), result, 0.001,
|
||||
"精度为0时应该返回整数");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试舍入模式为null的情况(应使用默认的HALF_UP模式)
|
||||
*/
|
||||
@Test
|
||||
public void testRandomDoubleWithNullRoundingMode() {
|
||||
final double result = RandomUtil.randomDouble(10.0, 2, null);
|
||||
|
||||
// 验证结果在[0, 10)范围内
|
||||
assertTrue(result >= 0.0 && result < 10.0,
|
||||
"随机数应该在[0, 10)范围内");
|
||||
|
||||
// 验证小数位数不超过2位
|
||||
final String resultStr = String.valueOf(result);
|
||||
if (resultStr.contains(".")) {
|
||||
final int decimalPlaces = resultStr.length() - resultStr.indexOf('.') - 1;
|
||||
assertTrue(decimalPlaces <= 2,
|
||||
"小数位数应该不超过2位,实际:" + decimalPlaces);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试边界情况:limit为较小值
|
||||
*/
|
||||
@Test
|
||||
public void testRandomDoubleWithSmallLimit() {
|
||||
final double result = RandomUtil.randomDouble(0.001, 5, RoundingMode.HALF_UP);
|
||||
|
||||
// 验证结果在[0, 0.001)范围内
|
||||
assertTrue(result >= 0.0 && result < 0.001,
|
||||
"随机数应该在[0, 0.001)范围内,实际值:" + result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试较大精度的情况
|
||||
*/
|
||||
@Test
|
||||
public void testRandomDoubleWithHighPrecision() {
|
||||
final double result = RandomUtil.randomDouble(100.0, 10, RoundingMode.HALF_UP);
|
||||
|
||||
// 验证结果在[0, 100)范围内
|
||||
assertTrue(result >= 0.0 && result < 100.0,
|
||||
"随机数应该在[0, 100)范围内");
|
||||
|
||||
// 验证结果经过了精度处理
|
||||
final String resultStr = String.valueOf(result);
|
||||
if (resultStr.contains(".")) {
|
||||
final int decimalPlaces = resultStr.length() - resultStr.indexOf('.') - 1;
|
||||
assertTrue(decimalPlaces <= 10,
|
||||
"小数位数应该不超过10位,实际:" + decimalPlaces);
|
||||
}
|
||||
final Pattern pattern = Pattern.compile("\\d+");
|
||||
return pattern.matcher(str).matches();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,467 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Hutool Team.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hutool.v7.core.util;
|
||||
|
||||
import cn.hutool.v7.core.date.DateField;
|
||||
import cn.hutool.v7.core.date.DateTime;
|
||||
import cn.hutool.v7.core.date.DateUnit;
|
||||
import cn.hutool.v7.core.date.DateUtil;
|
||||
import cn.hutool.v7.core.lang.selector.WeightObj;
|
||||
import cn.hutool.v7.core.lang.selector.WeightRandomSelector;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* RandomUtil 单元测试类
|
||||
* 基于 JUnit 5 实现,覆盖所有核心方法的功能验证
|
||||
*/
|
||||
public class TestRandomUtilByDoubao {
|
||||
|
||||
// ===================== 基础随机数生成测试 =====================
|
||||
@Test
|
||||
void testGetRandom() {
|
||||
// 测试普通随机数生成器
|
||||
final ThreadLocalRandom random = RandomUtil.getRandom();
|
||||
assertNotNull(random);
|
||||
|
||||
// 测试安全随机数生成器
|
||||
final Random secureRandom = RandomUtil.getRandom(true);
|
||||
assertInstanceOf(SecureRandom.class, secureRandom);
|
||||
|
||||
// 测试非安全随机数生成器
|
||||
final Random normalRandom = RandomUtil.getRandom(false);
|
||||
assertInstanceOf(ThreadLocalRandom.class, normalRandom);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRandomBoolean() {
|
||||
// 验证生成的布尔值在多次调用中会出现 true 和 false
|
||||
boolean hasTrue = false;
|
||||
boolean hasFalse = false;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
final boolean result = RandomUtil.randomBoolean();
|
||||
if (result) {
|
||||
hasTrue = true;
|
||||
} else {
|
||||
hasFalse = true;
|
||||
}
|
||||
if (hasTrue && hasFalse) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue(hasTrue && hasFalse);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRandomBytes() {
|
||||
// 测试随机字节数组长度
|
||||
final int length = 10;
|
||||
final byte[] bytes = RandomUtil.randomBytes(length);
|
||||
assertEquals(length, bytes.length);
|
||||
|
||||
// 测试指定随机数生成器的字节数组
|
||||
final byte[] bytesWithRandom = RandomUtil.randomBytes(length, new Random());
|
||||
assertEquals(length, bytesWithRandom.length);
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnnecessaryUnicodeEscape")
|
||||
@Test
|
||||
void testRandomChinese() {
|
||||
// 验证生成的字符是汉字(Unicode 范围:\u4E00 - \u9FFF)
|
||||
final char chineseChar = RandomUtil.randomChinese();
|
||||
assertTrue(chineseChar >= '\u4E00' && chineseChar <= '\u9FFF');
|
||||
}
|
||||
|
||||
// ===================== 整数随机数测试 =====================
|
||||
@SuppressWarnings("ConstantValue")
|
||||
@Test
|
||||
void testRandomInt() {
|
||||
// 测试无参随机整数
|
||||
final int randomInt = RandomUtil.randomInt();
|
||||
assertTrue(randomInt >= Integer.MIN_VALUE && randomInt <= Integer.MAX_VALUE);
|
||||
|
||||
// 测试 [0, limit) 范围
|
||||
final int limit = 100;
|
||||
final int intWithLimit = RandomUtil.randomInt(limit);
|
||||
assertTrue(intWithLimit >= 0 && intWithLimit < limit);
|
||||
|
||||
// 测试 [min, max) 范围
|
||||
final int min = 10;
|
||||
final int max = 20;
|
||||
final int intInRange = RandomUtil.randomInt(min, max);
|
||||
assertTrue(intInRange >= min && intInRange < max);
|
||||
|
||||
// 测试包含最大值的情况
|
||||
final int intWithMax = RandomUtil.randomInt(min, max, true, true);
|
||||
assertTrue(intWithMax >= min && intWithMax <= max);
|
||||
|
||||
// 测试不包含最小值的情况
|
||||
final int intWithoutMin = RandomUtil.randomInt(min, max, false, false);
|
||||
assertTrue(intWithoutMin > min && intWithoutMin < max);
|
||||
|
||||
// 测试随机索引数组
|
||||
final int[] randomInts = RandomUtil.randomInts(5);
|
||||
assertEquals(5, randomInts.length);
|
||||
// 验证索引是 0-4 的乱序排列
|
||||
final Set<Integer> indexSet = new HashSet<>();
|
||||
for (final int num : randomInts) {
|
||||
indexSet.add(num);
|
||||
assertTrue(num >= 0 && num < 5);
|
||||
}
|
||||
assertEquals(5, indexSet.size());
|
||||
}
|
||||
|
||||
// ===================== 长整数随机数测试 =====================
|
||||
@SuppressWarnings("ConstantValue")
|
||||
@Test
|
||||
void testRandomLong() {
|
||||
// 测试无参随机长整数
|
||||
final long randomLong = RandomUtil.randomLong();
|
||||
assertTrue(randomLong >= Long.MIN_VALUE && randomLong <= Long.MAX_VALUE);
|
||||
|
||||
// 测试 [0, limit) 范围
|
||||
final long limit = 1000L;
|
||||
final long longWithLimit = RandomUtil.randomLong(limit);
|
||||
assertTrue(longWithLimit >= 0 && longWithLimit < limit);
|
||||
|
||||
// 测试 [min, max) 范围
|
||||
final long min = 100L;
|
||||
final long max = 200L;
|
||||
final long longInRange = RandomUtil.randomLong(min, max);
|
||||
assertTrue(longInRange >= min && longInRange < max);
|
||||
|
||||
// 测试包含最大值的情况
|
||||
final long longWithMax = RandomUtil.randomLong(min, max, true, true);
|
||||
assertTrue(longWithMax >= min && longWithMax <= max);
|
||||
}
|
||||
|
||||
// ===================== 浮点数随机数测试 =====================
|
||||
@Test
|
||||
void testRandomFloat() {
|
||||
// 测试 [0, 1) 范围
|
||||
final float float01 = RandomUtil.randomFloat();
|
||||
assertTrue(float01 >= 0 && float01 < 1);
|
||||
|
||||
// 测试 [0, limit) 范围
|
||||
final float limit = 100.0f;
|
||||
final float floatWithLimit = RandomUtil.randomFloat(limit);
|
||||
assertTrue(floatWithLimit >= 0 && floatWithLimit < limit);
|
||||
|
||||
// 测试 [min, max) 范围
|
||||
final float min = 10.0f;
|
||||
final float max = 20.0f;
|
||||
final float floatInRange = RandomUtil.randomFloat(min, max);
|
||||
assertTrue(floatInRange >= min && floatInRange < max);
|
||||
|
||||
// 测试最小值等于最大值的情况
|
||||
final float floatEqual = RandomUtil.randomFloat(min, min);
|
||||
assertEquals(min, floatEqual);
|
||||
}
|
||||
|
||||
// ===================== 双精度浮点数随机数测试 =====================
|
||||
@Test
|
||||
void testRandomDouble() {
|
||||
// 测试 [0, 1) 范围
|
||||
final double double01 = RandomUtil.randomDouble();
|
||||
assertTrue(double01 >= 0 && double01 < 1);
|
||||
|
||||
// 测试 [0, limit) 范围
|
||||
final double limit = 1000.0;
|
||||
final double doubleWithLimit = RandomUtil.randomDouble(limit);
|
||||
assertTrue(doubleWithLimit >= 0 && doubleWithLimit < limit);
|
||||
|
||||
// 测试 [min, max) 范围
|
||||
final double min = 100.0;
|
||||
final double max = 200.0;
|
||||
final double doubleInRange = RandomUtil.randomDouble(min, max);
|
||||
assertTrue(doubleInRange >= min && doubleInRange < max);
|
||||
|
||||
// 测试保留小数位数
|
||||
final double doubleWithScale = RandomUtil.randomDouble(min, max, 2, RoundingMode.HALF_UP);
|
||||
// 验证小数位数不超过 2 位
|
||||
final String doubleStr = String.valueOf(doubleWithScale);
|
||||
int dotIndex = doubleStr.indexOf('.');
|
||||
if (dotIndex != -1) {
|
||||
assertTrue(doubleStr.length() - dotIndex - 1 <= 2);
|
||||
}
|
||||
|
||||
// 测试无范围保留小数
|
||||
final double doubleScaleOnly = RandomUtil.randomDouble(3, RoundingMode.HALF_UP);
|
||||
final String scaleStr = String.valueOf(doubleScaleOnly);
|
||||
dotIndex = scaleStr.indexOf('.');
|
||||
if (dotIndex != -1) {
|
||||
assertTrue(scaleStr.length() - dotIndex - 1 <= 3);
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== 高精度小数随机数测试 =====================
|
||||
@Test
|
||||
void testRandomBigDecimal() {
|
||||
// 测试 [0, 1) 范围
|
||||
final BigDecimal bd01 = RandomUtil.randomBigDecimal();
|
||||
assertTrue(bd01.compareTo(BigDecimal.ZERO) >= 0 && bd01.compareTo(BigDecimal.ONE) < 0);
|
||||
|
||||
// 测试 [0, limit) 范围
|
||||
final BigDecimal limit = new BigDecimal("100.0");
|
||||
final BigDecimal bdWithLimit = RandomUtil.randomBigDecimal(limit);
|
||||
assertTrue(bdWithLimit.compareTo(BigDecimal.ZERO) >= 0 && bdWithLimit.compareTo(limit) < 0);
|
||||
|
||||
// 测试 [min, max) 范围
|
||||
final BigDecimal min = new BigDecimal("10.0");
|
||||
final BigDecimal max = new BigDecimal("20.0");
|
||||
final BigDecimal bdInRange = RandomUtil.randomBigDecimal(min, max);
|
||||
assertTrue(bdInRange.compareTo(min) >= 0 && bdInRange.compareTo(max) < 0);
|
||||
}
|
||||
|
||||
// ===================== 随机元素选取测试 =====================
|
||||
@Test
|
||||
void testRandomEle() {
|
||||
// 测试列表随机元素
|
||||
final List<String> list = Arrays.asList("A", "B", "C", "D");
|
||||
final String randomEle = RandomUtil.randomEle(list);
|
||||
assertTrue(list.contains(randomEle));
|
||||
|
||||
// 测试列表前 N 项随机元素
|
||||
final String randomEleLimit = RandomUtil.randomEle(list, 2);
|
||||
assertTrue(Arrays.asList("A", "B").contains(randomEleLimit));
|
||||
|
||||
// 测试数组随机元素
|
||||
final String[] array = {"X", "Y", "Z"};
|
||||
final String randomArrayEle = RandomUtil.randomEle(array);
|
||||
assertTrue(Arrays.asList(array).contains(randomArrayEle));
|
||||
|
||||
// 测试数组前 N 项随机元素
|
||||
final String randomArrayEleLimit = RandomUtil.randomEle(array, 2);
|
||||
assertTrue(Arrays.asList("X", "Y").contains(randomArrayEleLimit));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRandomEles() {
|
||||
// 测试随机获取多个元素(允许重复)
|
||||
final List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
|
||||
final List<Integer> randomEles = RandomUtil.randomEles(list, 3);
|
||||
assertEquals(3, randomEles.size());
|
||||
for (final Integer num : randomEles) {
|
||||
assertTrue(list.contains(num));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRandomPick() {
|
||||
// 测试随机选取不重复位置的元素
|
||||
final List<String> list = Arrays.asList("a", "b", "c", "d", "e");
|
||||
final List<String> picked = RandomUtil.randomPick(list, 3);
|
||||
assertEquals(3, picked.size());
|
||||
// 验证选取的元素都是原列表中的
|
||||
for (final String s : picked) {
|
||||
assertTrue(list.contains(s));
|
||||
}
|
||||
|
||||
// 测试选取数量大于等于列表长度的情况
|
||||
final List<String> pickedAll = RandomUtil.randomPick(list, 10);
|
||||
assertEquals(list.size(), pickedAll.size());
|
||||
assertEquals(new HashSet<>(list), new HashSet<>(pickedAll));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRandomPickInts() {
|
||||
// 测试随机选取整数数组元素
|
||||
final int[] seed = {1, 2, 3, 4, 5};
|
||||
final int[] pickedInts = RandomUtil.randomPickInts(3, seed.clone());
|
||||
assertEquals(3, pickedInts.length);
|
||||
// 验证选取的元素都是原数组中的
|
||||
final Set<Integer> seedSet = new HashSet<>();
|
||||
for (final int num : seed) {
|
||||
seedSet.add(num);
|
||||
}
|
||||
for (final int num : pickedInts) {
|
||||
assertTrue(seedSet.contains(num));
|
||||
}
|
||||
|
||||
// 测试选取数量超过种子长度的异常
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||
RandomUtil.randomPickInts(10, seed);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRandomEleSet() {
|
||||
// 测试随机获取不重复元素集合
|
||||
final List<String> list = Arrays.asList("1", "2", "3", "4", "5", "1", "2");
|
||||
final Set<String> randomSet = RandomUtil.randomEleSet(list, 3);
|
||||
assertEquals(3, randomSet.size());
|
||||
// 验证元素都是原列表中的去重元素
|
||||
final Set<String> distinctSet = new HashSet<>(list);
|
||||
for (final String s : randomSet) {
|
||||
assertTrue(distinctSet.contains(s));
|
||||
}
|
||||
|
||||
// 测试选取数量超过去重后长度的异常
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||
RandomUtil.randomEleSet(list, 10);
|
||||
});
|
||||
}
|
||||
|
||||
// ===================== 随机字符串生成测试 =====================
|
||||
@Test
|
||||
void testRandomString() {
|
||||
final int length = 8;
|
||||
|
||||
// 测试数字+大小写字母
|
||||
final String lettersAndNumbers = RandomUtil.randomLettersAndNumbers(length);
|
||||
assertEquals(length, lettersAndNumbers.length());
|
||||
assertTrue(lettersAndNumbers.matches("[0-9A-Za-z]+"));
|
||||
|
||||
// 测试数字+小写字母
|
||||
final String lower = RandomUtil.randomLettersAndNumbersLower(length);
|
||||
assertEquals(length, lower.length());
|
||||
assertTrue(lower.matches("[0-9a-z]+"));
|
||||
|
||||
// 测试数字+大写字母
|
||||
final String upper = RandomUtil.randomLettersAndNumbersUpper(length);
|
||||
assertEquals(length, upper.length());
|
||||
assertTrue(upper.matches("[0-9A-Z]+"));
|
||||
|
||||
// 测试排除指定字符
|
||||
final String withoutStr = RandomUtil.randomLettersAndNumbersWithoutStr(length, "0OlL1");
|
||||
assertEquals(length, withoutStr.length());
|
||||
Assertions.assertFalse(withoutStr.matches(".*[0OlL1].*"));
|
||||
|
||||
// 测试小写字母+数字排除指定字符
|
||||
final String lowerWithout = RandomUtil.randomLettersAndNumbersLowerWithoutStr(length, "0OlL1");
|
||||
assertEquals(length, lowerWithout.length());
|
||||
Assertions.assertFalse(lowerWithout.matches(".*[0ol1].*"));
|
||||
|
||||
// 测试纯数字
|
||||
final String numbers = RandomUtil.randomNumbers(length);
|
||||
assertEquals(length, numbers.length());
|
||||
assertTrue(numbers.matches("[0-9]+"));
|
||||
|
||||
// 测试纯字母
|
||||
final String letters = RandomUtil.randomLetters(length);
|
||||
assertEquals(length, letters.length());
|
||||
assertTrue(letters.matches("[A-Za-z]+"));
|
||||
|
||||
// 测试纯小写字母
|
||||
final String lettersLower = RandomUtil.randomLettersLower(length);
|
||||
assertEquals(length, lettersLower.length());
|
||||
assertTrue(lettersLower.matches("[a-z]+"));
|
||||
|
||||
// 测试纯大写字母
|
||||
final String lettersUpper = RandomUtil.randomLettersUpper(length);
|
||||
assertEquals(length, lettersUpper.length());
|
||||
assertTrue(lettersUpper.matches("[A-Z]+"));
|
||||
|
||||
// 测试自定义字符集
|
||||
final String custom = RandomUtil.randomString("abc123", length);
|
||||
assertEquals(length, custom.length());
|
||||
assertTrue(custom.matches("[abc123]+"));
|
||||
|
||||
// 测试空字符集异常
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||
RandomUtil.randomString("", length);
|
||||
});
|
||||
}
|
||||
|
||||
// ===================== 随机字符生成测试 =====================
|
||||
@Test
|
||||
void testRandomChar() {
|
||||
// 测试随机数字字符
|
||||
final char numberChar = RandomUtil.randomNumber();
|
||||
assertTrue(Character.isDigit(numberChar));
|
||||
|
||||
// 测试随机小写字母+数字字符
|
||||
final char charLower = RandomUtil.randomChar();
|
||||
assertTrue(Character.isDigit(charLower) || (charLower >= 'a' && charLower <= 'z'));
|
||||
|
||||
// 测试自定义字符集字符
|
||||
final char customChar = RandomUtil.randomChar("ABC123");
|
||||
assertTrue("ABC123".indexOf(customChar) != -1);
|
||||
|
||||
// 测试字符数组随机字符
|
||||
final char[] chars = {'X', 'Y', 'Z'};
|
||||
final char arrayChar = RandomUtil.randomChar(chars);
|
||||
assertTrue(Arrays.asList('X', 'Y', 'Z').contains(arrayChar));
|
||||
|
||||
// 测试随机字符数组生成
|
||||
final char[] randomChars = RandomUtil.randomChars(chars, 5);
|
||||
assertEquals(5, randomChars.length);
|
||||
for (final char c : randomChars) {
|
||||
assertTrue(Arrays.asList('X', 'Y', 'Z').contains(c));
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== 权重随机测试 =====================
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
void testWeightRandom() {
|
||||
// 构建权重对象列表
|
||||
final WeightObj<String> obj1 = new WeightObj<>("A", 1);
|
||||
final WeightObj<String> obj2 = new WeightObj<>("B", 9);
|
||||
final List<WeightObj<String>> weightObjs = Arrays.asList(obj1, obj2);
|
||||
|
||||
// 测试数组形式的权重随机
|
||||
final WeightRandomSelector<String> selector1 = RandomUtil.weightRandom(weightObjs.toArray(new WeightObj[0]));
|
||||
// 测试迭代器形式的权重随机
|
||||
final WeightRandomSelector<String> selector2 = RandomUtil.weightRandom(weightObjs);
|
||||
|
||||
// 验证多次随机后,权重高的元素出现概率更高(概率性验证)
|
||||
int countA = 0;
|
||||
int countB = 0;
|
||||
final int total = 10000;
|
||||
for (int i = 0; i < total; i++) {
|
||||
final String result = selector1.select();
|
||||
if ("A".equals(result)) {
|
||||
countA++;
|
||||
} else if ("B".equals(result)) {
|
||||
countB++;
|
||||
}
|
||||
}
|
||||
// 验证 A 的出现概率约 10%,B 约 90%(允许 ±2% 误差)
|
||||
assertTrue(countA >= 800 && countA <= 1200);
|
||||
assertTrue(countB >= 8800 && countB <= 9200);
|
||||
}
|
||||
|
||||
// ===================== 随机日期测试 =====================
|
||||
@Test
|
||||
void testRandomDate() {
|
||||
// 测试基于当天的随机天数
|
||||
final DateTime randomDay = RandomUtil.randomDay(-5, 5);
|
||||
// 验证日期在 [-5, 4] 天范围内(因为 max 不包含)
|
||||
final long diff = DateUtil.betweenDay(DateUtil.now(), randomDay, true);
|
||||
assertTrue(diff >= -5 && diff <= 4);
|
||||
|
||||
// 测试基于指定日期的随机时间
|
||||
final DateTime baseDate = DateUtil.parse("2024-01-01 12:00:00");
|
||||
final DateTime randomDate = RandomUtil.randomDate(baseDate, DateField.HOUR_OF_DAY, -2, 3);
|
||||
// 验证小时偏移在 [-2, 2] 范围内
|
||||
final long hourDiff = DateUtil.between(baseDate, randomDate, DateUnit.HOUR);
|
||||
assertTrue(hourDiff >= -2 && hourDiff <= 2);
|
||||
|
||||
// 测试空基准日期
|
||||
final DateTime randomDateWithNull = RandomUtil.randomDate(null, DateField.MINUTE, -10, 10);
|
||||
assertNotNull(randomDateWithNull);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user