| 特性 | java.util.Random | Math.random() |
|---|---|---|
| 返回類型 | int/long/float/double/boolean/Gaussian | 僅 double (0.0~1.0) |
| 種子控制 | 支持指定種子,結果可復現 | 不可控,系統時間種子 |
| 線程安全 | 同步方法,多線程有鎖競爭 | 內部同步,同樣有競爭 |
| 性能 | 較高,可復用實例 | 每次調用創建 Random 實例 |
| 適用場景 | 通用隨機數、需復現、多類型 | 簡單臨時需求、單次調用 |
Random random = new Random(); // 系統時間種子
Random random = new Random(100L); // 指定種子,結果固定
random.nextInt(); // 隨機 int (含負數)
random.nextInt(100); // [0, 100) 隨機 int
random.nextLong(); // 隨機 long
random.nextDouble(); // [0.0, 1.0) 隨機 double
random.nextFloat(); // [0.0, 1.0) 隨機 float
random.nextBoolean(); // 隨機 boolean
random.nextGaussian(); // 高斯分布 (均值0,標準差1)
// 方式一:Random.nextInt (推薦)
int randomInt = random.nextInt(max - min + 1) + min;
// 方式二:Math.random
int randomInt = (int) (Math.random() * (max - min + 1)) + min;
// 方式三:ThreadLocalRandom (JDK 7+, 多線程高性能)
int randomInt = ThreadLocalRandom.current().nextInt(min, max + 1);
int n = 100;
int r1 = random.nextInt(n); // 最簡潔
int r2 = Math.abs(random.nextInt()) % n; // 兼容舊代碼寫法
int r3 = (int) (Math.random() * n);
// 保留 2 位小數 [0.00, 100.00]
double r = Math.round(random.nextDouble() * 10000) / 100.0;
// 或
double r = new BigDecimal(random.nextDouble() * 100).setScale(2, RoundingMode.HALF_UP).doubleValue();
public static List<Integer> distinctRandom(int count, int min, int max) {
if (count > (max - min + 1)) throw new IllegalArgumentException("範圍不足");
Set<Integer> set = new LinkedHashSet<>(); // 保持插入順序
Random random = new Random();
while (set.size() < count) {
set.add(random.nextInt(max - min + 1) + min);
}
return new ArrayList<>(set);
}
// JDK 8+ Stream 寫法
public static int[] distinctRandomStream(int count, int min, int max) {
return ThreadLocalRandom.current()
.ints(min, max + 1)
.distinct()
.limit(count)
.toArray();
}
public static <T> T weightedRandom(Map<T, Integer> weightMap) {
int totalWeight = weightMap.values().stream().mapToInt(Integer::intValue).sum();
int randomWeight = ThreadLocalRandom.current().nextInt(totalWeight);
int cumulative = 0;
for (Map.Entry<T, Integer> entry : weightMap.entrySet()) {
cumulative += entry.getValue();
if (randomWeight < cumulative) {
return entry.getKey();
}
}
throw new IllegalStateException("權重計算異常");
}
// 固定種子,每次運行序列相同
Random seededRandom = new Random(12345L);
for (int i = 0; i < 5; i++) {
System.out.println(seededRandom.nextInt(100));
}
// 輸出固定:51, 78, 12, 34, 90...
JDK 7 引入 java.util.concurrent.ThreadLocalRandom,每線程獨立實例,無鎖競爭,性能遠超 Random 和 Math.random()。
// 並行流中使用
List<Integer> list = ThreadLocalRandom.current()
.ints(1000, 1, 101)
.boxed()
.collect(Collectors.toList());
Random 非加密安全,種子可預測。安全敏感場景(Token、Session ID、加密密鑰)必須使用:
SecureRandom secureRandom = new SecureRandom();
byte[] token = new byte[32];
secureRandom.nextBytes(token);
String secureToken = Base64.getUrlEncoder().withoutPadding().encodeToString(token);
ThreadLocalRandom.current().nextInt(min, max+1)new Random(seed)(int)(Math.random() * range) + minSecureRandomThreadLocalRandom + Stream API