Math.random() 是 Java 中用于生成伪随机数的便捷方法,返回一个大于等于 0.0 且小于 1.0 的 double 类型随机数。


一、方法定义

public static double random()
  • 参数:无
  • 返回值
    • 返回 double 类型,满足 0.0 <= 返回值 < 1.0
  • 异常:无

⚠️ 注意:该方法是线程安全的,内部使用原子操作确保多线程环境下的正确性。


二、功能说明

1. 基本行为

  • 生成一个均匀分布在 [0.0, 1.0) 区间内的伪随机数
  • 包含 0.0,但不包含 1.0(左闭右开区间)
  • 使用线程本地的 Random 实例,避免竞争

2. 内部实现机制

  • 首次调用时创建一个 java.util.Random 实例(线程本地)
  • 后续调用复用该实例
  • 等价于:new Random().nextDouble()

3. 随机性质量

  • 使用线性同余生成器(LCG)
  • 适用于一般用途,但不适合加密场景
  • 对于高要求的随机性需求,建议使用 java.security.SecureRandom

三、示例代码

1. 基本使用

public class RandomExample {
    public static void main(String[] args) {
        // 生成 [0.0, 1.0) 之间的随机数
        System.out.println("随机数: " + Math.random());
        System.out.println("随机数: " + Math.random());
        System.out.println("随机数: " + Math.random());
    }
}

2. 生成指定范围的整数

// 生成 [min, max] 之间的随机整数(包含边界)
public static int randomInt(int min, int max) {
    return (int)(Math.random() * (max - min + 1)) + min;
}

// 使用示例
System.out.println("1-6 的随机数(模拟骰子): " + randomInt(1, 6));
System.out.println("0-99 的随机数: " + randomInt(0, 99));

3. 生成指定范围的浮点数

// 生成 [min, max) 之间的随机浮点数
public static double randomDouble(double min, double max) {
    return Math.random() * (max - min) + min;
}

// 使用示例
System.out.println("1.0-10.0 的随机数: " + randomDouble(1.0, 10.0));
System.out.println("-5.0-5.0 的随机数: " + randomDouble(-5.0, 5.0));

4. 随机布尔值

// 50% 概率返回 true
public static boolean randomBoolean() {
    return Math.random() < 0.5;
}

// 自定义概率
public static boolean randomChance(double probability) {
    return Math.random() < probability; // probability 为 0.0-1.0
}

// 使用示例
System.out.println("是否成功: " + randomChance(0.3)); // 30% 成功率

5. 随机选择数组元素

String[] colors = {"红", "橙", "黄", "绿", "蓝", "靛", "紫"};

public static <T> T randomChoice(T[] array) {
    if (array.length == 0) return null;
    int index = (int)(Math.random() * array.length);
    return array[index];
}

// 使用示例
System.out.println("随机颜色: " + randomChoice(colors));

四、使用技巧

1. 生成正态分布随机数

// 使用 Box-Muller 变换生成正态分布
public static double randomGaussian(double mean, double stdDev) {
    double u1 = Math.random();
    double u2 = Math.random();
    double z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
    return mean + stdDev * z;
}

// 生成均值为 100,标准差为 15 的正态分布(如 IQ 分数)
System.out.println("随机 IQ: " + randomGaussian(100, 15));

2. 随机打乱数组

public static void shuffleArray(int[] array) {
    for (int i = array.length - 1; i > 0; i--) {
        int j = (int)(Math.random() * (i + 1));
        // 交换 array[i] 和 array[j]
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

3. 设置种子(无法直接设置)

// 注意:Math.random() 无法直接设置种子
// 如需可重现的随机序列,应使用 Random 类
Random random = new Random(12345); // 固定种子
System.out.println(random.nextDouble());

五、常见错误

错误 说明 修正
期望包含 1.0 Math.random() 永远不返回 1.0 理解 [0.0, 1.0) 区间
整数转换错误 (int)(Math.random() * 10) 生成 0-9 使用 +1 调整范围
重复调用性能 高频调用时性能不如 Random 实例 对高频场景使用 Random 实例
期望加密安全 随机性不够强 使用 SecureRandom
忽视浮点精度 误以为能生成所有可能的 double 值 理解实际精度限制

六、注意事项

  1. 线程安全:方法本身是线程安全的
  2. 性能:首次调用有初始化开销,后续调用性能良好
  3. 可重现性:无法设置种子,生成的序列不可重现
  4. 精度限制double 有精度限制,不是所有 [0.0, 1.0) 的值都能生成
  5. 范围理解:始终是 [0.0, 1.0),包含 0.0,不包含 1.0
  6. 替代方案:Java 8+ 推荐使用 ThreadLocalRandomRandom

七、最佳实践与性能优化

实践 说明
✅ 一般用途使用 简单随机需求,如游戏、抽样
✅ 理解范围 明确 [0.0, 1.0) 的边界
⚠️ 高频调用考虑替代 使用 RandomThreadLocalRandom 实例
✅ 加密场景禁用 使用 SecureRandom
✅ 不可重现接受 如需重现性,使用 Random 并设置种子
✅ 单元测试注意 无法通过设置种子来测试确定性行为

性能对比示例:

// 场景:生成 100 万个随机数
// 方案1:Math.random()(每次调用都有同步开销)
long start = System.nanoTime();
for (int i = 0; i < 1_000_000; i++) {
    Math.random();
}
long time1 = System.nanoTime() - start;

// 方案2:Random 实例(推荐用于高频调用)
Random random = new Random();
start = System.nanoTime();
for (int i = 0; i < 1_000_000; i++) {
    random.nextDouble();
}
long time2 = System.nanoTime() - start;

System.out.println("Math.random(): " + time1 + " ns");
System.out.println("Random.nextDouble(): " + time2 + " ns");

建议:在性能关键的循环中,优先使用 RandomThreadLocalRandom


八、与其他随机方法对比

方法 优点 缺点 适用场景
Math.random() 简单易用,线程安全 无法设置种子,性能一般 简单随机需求
Random 可设置种子,多种方法 需要创建实例 需要重现性的场景
ThreadLocalRandom 高性能,线程专用 Java 7+ 高并发场景
SecureRandom 加密安全 性能差 安全敏感场景

九、总结

Math.random() 是 Java 中最简单的随机数生成方法,适合快速实现基本的随机功能。

核心要点:

  • 简单易用:无需创建对象,直接调用
  • 线程安全:内部处理并发问题
  • ⚠️ 不可设置种子:生成的序列不可重现
  • ⚠️ 性能一般:高频调用时不如 Random 实例
  • ⚠️ 非加密安全:不能用于安全敏感场景

使用建议:

  • 推荐使用:快速原型、简单游戏、教学示例
  • 谨慎使用:性能关键路径、需要重现性的测试
  • 避免使用:加密、安全令牌生成、高精度模拟

💡 提示:记住口诀——“简单随机用 random,高频并发选 ThreadLocalRandom,安全加密用 SecureRandom,需要重现建 Random”。在大多数日常编程中,Math.random() 是足够且方便的选择。