<p>Random.nextInt(int bound) 不包括上界。它返回[0, bound)范围内的整数,如nextInt(10)返回0~9;生成[min, max]需用nextInt(max - min + 1) + min;ThreadLocalRandom.nextInt(min, max)同理,bound仍为严格上界。</p>

Random.nextInt(int bound) 的边界到底包不包括上界?
不包括。这是最容易栽跟头的地方——nextInt(10) 返回的是 0 到 9(含),永远取不到 10。很多人误以为它像 Python 的 randint() 那样是闭区间,结果写成 nextInt(100) 想要 1–100,却得到 0–99。
想生成 [min, max](含两端)的整数,得手动平移和扩容:
int min = 5, max = 15; int random = rand.nextInt(max - min + 1) + min;
-
max - min + 1是真正的“范围长度”,确保能覆盖全部整数个数 -
+ min是偏移量,把起点从0拉到min - 如果
min > max,会抛IllegalArgumentException,务必校验输入
为什么不用 Math.random() * bound 再强转 int?
因为精度丢失和分布偏差。Math.random() 返回 double,乘法+截断可能让某些整数概率略低(尤其大范围时),而 Random.nextInt() 是基于均匀整数算法实现的,更可靠。
更关键的是:用 (int)(Math.random() * 10) 看似等价于 nextInt(10),但实际在极端情况下(比如并发多线程反复调用),Math.random() 共享一个全局 Random 实例,有锁竞争,性能差且不可控。
立即学习“Java免费学习笔记(深入)”;
- 单次简单脚本?凑合能用,但别写进工具类
- 高频调用或需要可重现性(比如 seed 控制)?必须用显式
Random实例 - Java 7+ 推荐用
ThreadLocalRandom.current().nextInt(min, max + 1),无锁、线程安全、语义清晰
ThreadLocalRandom.nextInt(min, max) 和 Random.nextInt(bound) 参数逻辑冲突吗?
不冲突,但命名容易混淆:ThreadLocalRandom.nextInt(int origin, int bound) 的 bound 是**严格上界**(不包含),和 Random.nextInt(int bound) 一致;而它的 origin 是下界(包含)。所以 nextInt(1, 101) 才真能生成 1–100。
注意这个重载只存在于 ThreadLocalRandom,Random 类没有 nextInt(int, int) 方法——直接写会编译报错 cannot resolve method nextInt(int, int)。
- 用
ThreadLocalRandom前必须确认运行在线程内(不能在 static 初始化块里提前调用) - 它不支持设 seed,调试时无法复现随机序列
- 若需 seed 控制(如游戏关卡、测试数据),老实用
new Random(seed).nextInt(...)
nextInt() 返回负数?是不是 bug?
不是 bug,是设计如此。当你传入负数作为 bound(比如 nextInt(-5)),JVM 会立即抛出 IllegalArgumentException: bound must be positive。但如果你没传参数、用了无参 nextInt()(返回 int 全范围),那结果当然可能为负——它返回的是完整的 32 位随机整数,范围是 [-2147483648, 2147483647]。
- 常见误操作:把
nextInt()当作“小范围随机”直接用,结果某次拿到负数,程序逻辑崩了 - 安全做法:除非明确需要全范围整数,否则一律用带参版本,并校验
bound > 0 - 如果真要负数区间(比如 [-10, -1]),按公式算:
rand.nextInt(10) - 10(即bound=10,再整体偏移 -10)
边界判断、参数含义、线程模型这三处稍不留神就会埋雷,尤其是从其他语言转过来的人,习惯性套用旧经验。最稳妥的做法:每次写之前,花三秒默念一遍——“bound 是排他的,origin 是包含的,seed 只属于你自己的 Random 实例”。










