All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.hutool.core.util.RandomUtil Maven / Gradle / Ivy

There is a newer version: 5.8.33
Show newest version
package cn.hutool.core.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.WeightRandom;
import cn.hutool.core.lang.WeightRandom.WeightObj;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 随机工具类
 *
 * @author xiaoleilu
 */
public class RandomUtil {

	/**
	 * 用于随机选的数字
	 */
	public static final String BASE_NUMBER = "0123456789";
	/**
	 * 用于随机选的字符
	 */
	public static final String BASE_CHAR = "abcdefghijklmnopqrstuvwxyz";
	/**
	 * 用于随机选的字符和数字(小写)
	 */
	public static final String BASE_CHAR_NUMBER_LOWER = BASE_CHAR + BASE_NUMBER;
	/**
	 * 用于随机选的字符和数字(包括大写和小写字母)
	 */
	public static final String BASE_CHAR_NUMBER = BASE_CHAR.toUpperCase() + BASE_CHAR_NUMBER_LOWER;

	// region ----- get or create Random

	/**
	 * 获取随机数生成器对象
* ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。 * *

* 注意:此方法返回的{@link ThreadLocalRandom}不可以在多线程环境下共享对象,否则有重复随机数问题。 * 见:https://www.jianshu.com/p/89dfe990295c *

* * @return {@link ThreadLocalRandom} * @since 3.1.2 */ public static ThreadLocalRandom getRandom() { return ThreadLocalRandom.current(); } /** * 创建{@link SecureRandom},类提供加密的强随机数生成器 (RNG)
* * @param seed 自定义随机种子 * @return {@link SecureRandom} * @since 4.6.5 */ public static SecureRandom createSecureRandom(final byte[] seed) { return (null == seed) ? new SecureRandom() : new SecureRandom(seed); } /** * 获取SHA1PRNG的{@link SecureRandom},类提供加密的强随机数生成器 (RNG)
* 注意:此方法获取的是伪随机序列发生器PRNG(pseudo-random number generator) * *

* 相关说明见:https://stackoverflow.com/questions/137212/how-to-solve-slow-java-securerandom * * @return {@link SecureRandom} * @since 3.1.2 */ public static SecureRandom getSecureRandom() { return getSecureRandom(null); } /** * 获取SHA1PRNG的{@link SecureRandom},类提供加密的强随机数生成器 (RNG)
* 注意:此方法获取的是伪随机序列发生器PRNG(pseudo-random number generator) * *

* 相关说明见:https://stackoverflow.com/questions/137212/how-to-solve-slow-java-securerandom * * @param seed 随机数种子 * @return {@link SecureRandom} * @see #createSecureRandom(byte[]) * @since 5.5.2 */ public static SecureRandom getSecureRandom(final byte[] seed) { return createSecureRandom(seed); } /** * 获取SHA1PRNG的{@link SecureRandom},类提供加密的强随机数生成器 (RNG)
* 注意:此方法获取的是伪随机序列发生器PRNG(pseudo-random number generator),在Linux下噪声生成时可能造成较长时间停顿。
* see: http://ifeve.com/jvm-random-and-entropy-source/ * *

* 相关说明见:https://stackoverflow.com/questions/137212/how-to-solve-slow-java-securerandom * * @param seed 随机数种子 * @return {@link SecureRandom} * @since 5.5.8 */ public static SecureRandom getSHA1PRNGRandom(final byte[] seed) { final SecureRandom random; try { random = SecureRandom.getInstance("SHA1PRNG"); } catch (final NoSuchAlgorithmException e) { throw new UtilException(e); } if (null != seed) { random.setSeed(seed); } return random; } /** * 获取algorithms/providers中提供的强安全随机生成器
* 注意:此方法可能造成阻塞或性能问题 * * @return {@link SecureRandom} * @since 5.7.12 */ public static SecureRandom getSecureRandomStrong() { try { return SecureRandom.getInstanceStrong(); } catch (final NoSuchAlgorithmException e) { throw new UtilException(e); } } /** * 获取随机数产生器 * * @param isSecure 是否为强随机数生成器 (RNG) * @return {@link Random} * @see #getSecureRandom() * @see #getRandom() * @since 4.1.15 */ public static Random getRandom(final boolean isSecure) { return isSecure ? getSecureRandom() : getRandom(); } // endregion /** * 获得随机Boolean值 * * @return true or false * @since 4.5.9 */ public static boolean randomBoolean() { return 0 == randomInt(2); } /** * 随机bytes * * @param length 长度 * @return bytes */ public static byte[] randomBytes(final int length) { final byte[] bytes = new byte[length]; getRandom().nextBytes(bytes); return bytes; } // region ----- randomInt /** * 获得随机数int值 * * @return 随机数 * @see Random#nextInt() */ public static int randomInt() { return getRandom().nextInt(); } /** * 获得指定范围内的随机数 [0,limit) * * @param limitExclude 限制随机数的范围,不包括这个数 * @return 随机数 * @see Random#nextInt(int) */ public static int randomInt(final int limitExclude) { return getRandom().nextInt(limitExclude); } /** * 获得指定范围内的随机数 * * @param minInclude 最小数(包含) * @param maxExclude 最大数(不包含) * @return 随机数 */ public static int randomInt(final int minInclude, final int maxExclude) { return randomInt(minInclude, maxExclude, true, false); } /** * 获得指定范围内的随机数 * * @param min 最小数 * @param max 最大数 * @param includeMin 是否包含最小值 * @param includeMax 是否包含最大值 * @return 随机数 */ public static int randomInt(int min, int max, final boolean includeMin, final boolean includeMax) { if (!includeMin) { min++; } if (includeMax) { max++; } return getRandom().nextInt(min, max); } /** * 创建指定长度的随机索引 * * @param length 长度 * @return 随机索引 * @since 5.2.1 */ public static int[] randomInts(final int length) { final int[] range = ArrayUtil.range(length); for (int i = 0; i < length; i++) { final int random = randomInt(i, length); ArrayUtil.swap(range, i, random); } return range; } // endregion // region ----- randomLong /** * 获得随机数 * * @return 随机数 * @see ThreadLocalRandom#nextLong() * @since 3.3.0 */ public static long randomLong() { return getRandom().nextLong(); } /** * 获得指定范围内的随机数 [0,limit) * * @param limitExclude 限制随机数的范围,不包括这个数 * @return 随机数 * @see ThreadLocalRandom#nextLong(long) */ public static long randomLong(final long limitExclude) { return getRandom().nextLong(limitExclude); } /** * 获得指定范围内的随机数[min, max) * * @param minInclude 最小数(包含) * @param maxExclude 最大数(不包含) * @return 随机数 * @see ThreadLocalRandom#nextLong(long, long) * @since 3.3.0 */ public static long randomLong(final long minInclude, final long maxExclude) { return randomLong(minInclude, maxExclude, true, false); } /** * 获得指定范围内的随机数 * * @param min 最小数 * @param max 最大数 * @param includeMin 是否包含最小值 * @param includeMax 是否包含最大值 * @return 随机数 */ public static long randomLong(long min, long max, final boolean includeMin, final boolean includeMax) { if (!includeMin) { min++; } if (includeMax) { max++; } return getRandom().nextLong(min, max); } // endregion // region ----- randomFloat /** * 获得随机数[0, 1) * * @return 随机数 * @see ThreadLocalRandom#nextFloat() */ public static float randomFloat() { return getRandom().nextFloat(); } /** * 获得指定范围内的随机数 [0,limit) * * @param limitExclude 限制随机数的范围,不包括这个数 * @return 随机数 */ public static float randomFloat(final float limitExclude) { return randomFloat(0, limitExclude); } /** * 获得指定范围内的随机数[min, max) * * @param minInclude 最小数(包含) * @param maxExclude 最大数(不包含) * @return 随机数 * @see ThreadLocalRandom#nextFloat() */ public static float randomFloat(final float minInclude, final float maxExclude) { if (minInclude == maxExclude) { return minInclude; } return minInclude + ((maxExclude - minInclude) * getRandom().nextFloat()); } // endregion // region ----- randomDouble /** * 获得指定范围内的随机数 * * @param minInclude 最小数(包含) * @param maxExclude 最大数(不包含) * @return 随机数 * @see ThreadLocalRandom#nextDouble(double, double) * @since 3.3.0 */ public static double randomDouble(final double minInclude, final double maxExclude) { return getRandom().nextDouble(minInclude, maxExclude); } /** * 获得指定范围内的随机数 * * @param minInclude 最小数(包含) * @param maxExclude 最大数(不包含) * @param scale 保留小数位数 * @param roundingMode 保留小数的模式 {@link RoundingMode} * @return 随机数 * @since 4.0.8 */ public static double randomDouble(final double minInclude, final double maxExclude, final int scale, final RoundingMode roundingMode) { return NumberUtil.round(randomDouble(minInclude, maxExclude), scale, roundingMode).doubleValue(); } /** * 获得随机数[0, 1) * * @return 随机数 * @see ThreadLocalRandom#nextDouble() * @since 3.3.0 */ public static double randomDouble() { return getRandom().nextDouble(); } /** * 获得指定范围内的随机数 * * @param scale 保留小数位数 * @param roundingMode 保留小数的模式 {@link RoundingMode} * @return 随机数 * @since 4.0.8 */ public static double randomDouble(final int scale, final RoundingMode roundingMode) { return NumberUtil.round(randomDouble(), scale, roundingMode).doubleValue(); } /** * 获得指定范围内的随机数 [0,limit) * * @param limit 限制随机数的范围,不包括这个数 * @return 随机数 * @see ThreadLocalRandom#nextDouble(double) * @since 3.3.0 */ public static double randomDouble(final double limit) { return getRandom().nextDouble(limit); } /** * 获得指定范围内的随机数 * * @param limit 限制随机数的范围,不包括这个数 * @param scale 保留小数位数 * @param roundingMode 保留小数的模式 {@link RoundingMode} * @return 随机数 * @since 4.0.8 */ public static double randomDouble(final double limit, final int scale, final RoundingMode roundingMode) { return NumberUtil.round(randomDouble(limit), scale, roundingMode).doubleValue(); } // endregion // region ----- randomBigDecimal /** * 获得指定范围内的随机数[0, 1) * * @return 随机数 * @since 4.0.9 */ public static BigDecimal randomBigDecimal() { return NumberUtil.toBigDecimal(getRandom().nextDouble()); } /** * 获得指定范围内的随机数 [0,limit) * * @param limit 最大数(不包含) * @return 随机数 * @since 4.0.9 */ public static BigDecimal randomBigDecimal(final BigDecimal limit) { return NumberUtil.toBigDecimal(getRandom().nextDouble(limit.doubleValue())); } /** * 获得指定范围内的随机数 * * @param minInclude 最小数(包含) * @param maxExclude 最大数(不包含) * @return 随机数 * @since 4.0.9 */ public static BigDecimal randomBigDecimal(final BigDecimal minInclude, final BigDecimal maxExclude) { return NumberUtil.toBigDecimal(getRandom().nextDouble(minInclude.doubleValue(), maxExclude.doubleValue())); } // endregion // region ----- randomEle /** * 随机获得列表中的元素 * * @param 元素类型 * @param list 列表 * @return 随机元素 */ public static T randomEle(final List list) { return randomEle(list, list.size()); } /** * 随机获得列表中的元素 * * @param 元素类型 * @param list 列表 * @param limit 限制列表的前N项 * @return 随机元素 */ public static T randomEle(final List list, int limit) { if (list.size() < limit) { limit = list.size(); } return list.get(randomInt(limit)); } /** * 随机获得数组中的元素 * * @param 元素类型 * @param array 列表 * @return 随机元素 * @since 3.3.0 */ public static T randomEle(final T[] array) { return randomEle(array, array.length); } /** * 随机获得数组中的元素 * * @param 元素类型 * @param array 列表 * @param limit 限制列表的前N项 * @return 随机元素 * @since 3.3.0 */ public static T randomEle(final T[] array, int limit) { if (array.length < limit) { limit = array.length; } return array[randomInt(limit)]; } /** * 随机获得列表中的一定量元素 * * @param 元素类型 * @param list 列表 * @param count 随机取出的个数 * @return 随机元素 */ public static List randomEles(final List list, final int count) { final List result = new ArrayList<>(count); final int limit = list.size(); while (result.size() < count) { result.add(randomEle(list, limit)); } return result; } /** * 随机获得列表中的一定量的元素,返回List
* 此方法与{@link #randomEles(List, int)} 不同点在于,不会获取重复位置的元素 * * @param source 列表 * @param count 随机取出的个数 * @param 元素类型 * @return 随机列表 * @since 5.2.1 */ public static List randomEleList(final List source, final int count) { if (count >= source.size()) { return ListUtil.toList(source); } final int[] randomList = ArrayUtil.sub(randomInts(source.size()), 0, count); final List result = new ArrayList<>(); for (final int e : randomList) { result.add(source.get(e)); } return result; } /** * 随机获得列表中的一定量的不重复元素,返回Set * * @param 元素类型 * @param collection 列表 * @param count 随机取出的个数 * @return 随机元素 * @throws IllegalArgumentException 需要的长度大于给定集合非重复总数 */ public static Set randomEleSet(final Collection collection, final int count) { final ArrayList source = CollUtil.distinct(collection); if (count > source.size()) { throw new IllegalArgumentException("Count is larger than collection distinct size !"); } final Set result = new LinkedHashSet<>(count); final int limit = source.size(); while (result.size() < count) { result.add(randomEle(source, limit)); } return result; } // endregion // region ----- randomString /** * 获得一个随机的字符串(只包含数字和字符) * * @param length 字符串的长度 * @return 随机字符串 */ public static String randomString(final int length) { return randomString(BASE_CHAR_NUMBER, length); } /** * 获得一个随机的字符串(只包含数字和大写字符) * * @param length 字符串的长度 * @return 随机字符串 * @since 4.0.13 */ public static String randomStringUpper(final int length) { return randomString(BASE_CHAR_NUMBER, length).toUpperCase(); } /** * 获得一个随机的字符串(只包含数字和字母) 并排除指定字符串 * * @param length 字符串的长度 * @param elemData 要排除的字符串,如:去重容易混淆的字符串,oO0、lL1、q9Q、pP,区分大小写 * @return 随机字符串 */ public static String randomStringWithoutStr(final int length, final String elemData) { String baseStr = BASE_CHAR_NUMBER; baseStr = StrUtil.removeAll(baseStr, elemData.toCharArray()); return randomString(baseStr, length); } /** * 获得一个随机的字符串(只包含数字和小写字母) 并排除指定字符串 * * @param length 字符串的长度 * @param elemData 要排除的字符串,如:去重容易混淆的字符串,oO0、lL1、q9Q、pP,不区分大小写 * @return 随机字符串 * @since 5.8.28 */ public static String randomStringLowerWithoutStr(final int length, final String elemData) { String baseStr = BASE_CHAR_NUMBER_LOWER; baseStr = StrUtil.removeAll(baseStr, elemData.toLowerCase().toCharArray()); return randomString(baseStr, length); } /** * 获得一个只包含数字的字符串 * * @param length 字符串的长度 * @return 随机字符串 */ public static String randomNumbers(final int length) { return randomString(BASE_NUMBER, length); } /** * 获得一个随机的字符串 * * @param baseString 随机字符选取的样本 * @param length 字符串的长度 * @return 随机字符串 */ public static String randomString(final String baseString, int length) { if (StrUtil.isEmpty(baseString)) { return StrUtil.EMPTY; } if (length < 1) { length = 1; } 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(); } // endregion // region ---- randomChar /** * 随机汉字('\u4E00'-'\u9FFF') * * @return 随机的汉字字符 * @since 5.7.15 */ @SuppressWarnings("UnnecessaryUnicodeEscape") public static char randomChinese() { return (char) randomInt('\u4E00', '\u9FFF'); } /** * 随机数字,数字为0~9单个数字 * * @return 随机数字字符 * @since 3.1.2 */ public static char randomNumber() { return randomChar(BASE_NUMBER); } /** * 随机字母或数字,小写 * * @return 随机字符 * @since 3.1.2 */ public static char randomChar() { return randomChar(BASE_CHAR_NUMBER); } /** * 随机字符 * * @param baseString 随机字符选取的样本 * @return 随机字符 * @since 3.1.2 */ public static char randomChar(final String baseString) { return baseString.charAt(randomInt(baseString.length())); } // endregion // region ----- weightRandom /** * 带有权重的随机生成器 * * @param 随机对象类型 * @param weightObjs 带有权重的对象列表 * @return {@link WeightRandom} * @since 4.0.3 */ public static WeightRandom weightRandom(final WeightObj[] weightObjs) { return new WeightRandom<>(weightObjs); } /** * 带有权重的随机生成器 * * @param 随机对象类型 * @param weightObjs 带有权重的对象列表 * @return {@link WeightRandom} * @since 4.0.3 */ public static WeightRandom weightRandom(final Iterable> weightObjs) { return new WeightRandom<>(weightObjs); } // endregion // region ----- randomDate /** * 以当天为基准,随机产生一个日期 * * @param min 偏移最小天,可以为负数表示过去的时间(包含) * @param max 偏移最大天,可以为负数表示过去的时间(不包含) * @return 随机日期(随机天,其它时间不变) * @since 4.0.8 */ public static DateTime randomDay(final int min, final int max) { return randomDate(DateUtil.date(), DateField.DAY_OF_YEAR, min, max); } /** * 以给定日期为基准,随机产生一个日期 * * @param baseDate 基准日期 * @param dateField 偏移的时间字段,例如时、分、秒等 * @param min 偏移最小量,可以为负数表示过去的时间(包含) * @param max 偏移最大量,可以为负数表示过去的时间(不包含) * @return 随机日期 * @since 4.5.8 */ public static DateTime randomDate(Date baseDate, final DateField dateField, final int min, final int max) { if (null == baseDate) { baseDate = DateUtil.date(); } return DateUtil.offset(baseDate, dateField, randomInt(min, max)); } // endregion }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy