diff --git a/plusone-commons/src/main/java/xyz/zhouxy/plusone/commons/util/RandomTools.java b/plusone-commons/src/main/java/xyz/zhouxy/plusone/commons/util/RandomTools.java
index 376cbca..d9d2841 100644
--- a/plusone-commons/src/main/java/xyz/zhouxy/plusone/commons/util/RandomTools.java
+++ b/plusone-commons/src/main/java/xyz/zhouxy/plusone/commons/util/RandomTools.java
@@ -24,6 +24,9 @@ import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
+import com.google.common.collect.BoundType;
+import com.google.common.collect.Range;
+
/**
* 随机工具类
*
@@ -116,6 +119,52 @@ public final class RandomTools {
return randomStrInternal(DEFAULT_SECURE_RANDOM, sourceCharacters, length);
}
+ /**
+ * 生成随机整数
+ *
+ * @param min 最小值(包含)
+ * @param max 最大值(不包含)
+ * @return 在区间 {@code [min, max)} 内的随机整数
+ */
+ public static int randomInt(int min, int max) {
+ return randomIntInternal(ThreadLocalRandom.current(), min, max);
+ }
+
+ /**
+ * 生成随机整数
+ *
+ * @param min 最小值(包含)
+ * @param max 最大值(不包含)
+ * @return 在区间 {@code [min, max)} 内的随机整数
+ */
+ public static int randomInt(Random random, int min, int max) {
+ checkArgumentNotNull(random, "Random cannot be null.");
+ return randomIntInternal(random, min, max);
+ }
+
+ /**
+ * 生成随机整数
+ *
+ * @param range 整数区间
+ * @return 在指定区间内的随机整数
+ */
+ public static int randomInt(Range range) {
+ checkArgumentNotNull(range, "Range cannot be null.");
+ return randomIntInternal(ThreadLocalRandom.current(), range);
+ }
+
+ /**
+ * 生成随机整数
+ *
+ * @param range 整数区间
+ * @return 在指定区间内的随机整数
+ */
+ public static int randomInt(Random random, Range range) {
+ checkArgumentNotNull(random, "Random cannot be null.");
+ checkArgumentNotNull(range, "Range cannot be null.");
+ return randomIntInternal(random, range);
+ }
+
/**
* 使用传入的随机数生成器,生成指定长度的字符串
*
@@ -158,6 +207,31 @@ public final class RandomTools {
return String.valueOf(result);
}
+ /**
+ * 生成随机整数
+ *
+ * @param min 最小值(包含)
+ * @param max 最大值(不包含)
+ * @return 在区间 {@code [min, max)} 内的随机整数
+ */
+ private static int randomIntInternal(Random random, int min, int max) {
+ return random.nextInt(max - min) + min;
+ }
+
+ /**
+ * 生成随机整数
+ *
+ * @param range 整数区间
+ * @return 在指定区间内的随机整数
+ */
+ private static int randomIntInternal(Random random, Range range) {
+ Integer lowerEndpoint = range.lowerEndpoint();
+ Integer upperEndpoint = range.upperEndpoint();
+ int min = range.lowerBoundType() == BoundType.CLOSED ? lowerEndpoint : lowerEndpoint + 1;
+ int max = range.upperBoundType() == BoundType.OPEN ? upperEndpoint : upperEndpoint + 1;
+ return random.nextInt(max - min) + min;
+ }
+
private RandomTools() {
throw new IllegalStateException("Utility class");
}
diff --git a/plusone-commons/src/test/java/xyz/zhouxy/plusone/commons/util/RandomToolsTests.java b/plusone-commons/src/test/java/xyz/zhouxy/plusone/commons/util/RandomToolsTests.java
index 7a05601..aa30262 100644
--- a/plusone-commons/src/test/java/xyz/zhouxy/plusone/commons/util/RandomToolsTests.java
+++ b/plusone-commons/src/test/java/xyz/zhouxy/plusone/commons/util/RandomToolsTests.java
@@ -21,6 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.reflect.Constructor;
import java.security.SecureRandom;
@@ -30,6 +31,8 @@ import java.util.Random;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import com.google.common.collect.Range;
+
@SuppressWarnings("null")
public class RandomToolsTests {
@@ -107,6 +110,50 @@ public class RandomToolsTests {
assertEquals(5, result.length());
}
+ @Test
+ public void randomInt_WithMinAndMax() {
+ for (int i = 0; i < 1000_0000; i++) {
+ int r = RandomTools.randomInt(random, -2, 3);
+ assertTrue(r >= -2 && r < 3);
+ }
+ }
+
+ @Test
+ public void randomInt_WithClosedOpenRange() {
+ Range co = Range.closedOpen(-2, 3);
+ for (int i = 0; i < 1000_0000; i++) {
+ int rco = RandomTools.randomInt(random, co);
+ assertTrue(rco >= -2 && rco < 3);
+ }
+ }
+
+ @Test
+ public void randomInt_WithClosedRange() {
+ Range cc = Range.closed(-2, 3);
+ for (int i = 0; i < 1000_0000; i++) {
+ int rcc = RandomTools.randomInt(random, cc);
+ assertTrue(rcc >= -2 && rcc <= 3);
+ }
+ }
+
+ @Test
+ public void randomInt_WithOpenClosedRange() {
+ Range oc = Range.openClosed(-2, 3);
+ for (int i = 0; i < 1000_0000; i++) {
+ int roc = RandomTools.randomInt(random, oc);
+ assertTrue(roc > -2 && roc <= 3);
+ }
+ }
+
+ @Test
+ public void randomInt_WithOpenRange() {
+ Range oo = Range.open(-2, 3);
+ for (int i = 0; i < 1000_0000; i++) {
+ int roo = RandomTools.randomInt(random, oo);
+ assertTrue(roo > -2 && roo < 3);
+ }
+ }
+
@Test
void test_constructor_isNotAccessible_ThrowsIllegalStateException() {
Constructor>[] constructors = RandomTools.class.getDeclaredConstructors();