Java的Math类用于实际数值处理,非数学学习;需自行处理NaN和无穷大;round、floor、ceil、rint行为各异,选错致结果偏移;sqrt比pow求根更优;三角函数以弧度为单位;Math.random()不适用于安全或高并发场景;所有方法static final,单元测试需策略抽离。

Java 的 Math 类不是用来“学数学”的,而是解决实际编码中绕不开的数值处理问题——四舍五入、取整、开方、三角计算、随机数生成等,都得靠它;但它不处理 NaN 或无穷大时的业务逻辑,这点必须自己兜底。
四舍五入和取整函数怎么选:round、floor、ceil、rint
它们行为差异明显,选错会导致结果偏移:
-
Math.round(double)实际是floor(x + 0.5),返回long;注意Math.round(-1.5)得-1(向正无穷方向舍入),不是“银行家舍入” -
Math.floor(double)总是向下取整(≤x 的最大整数),返回double;Math.floor(-1.2)→-2.0 -
Math.ceil(double)总是向上取整(≥x 的最小整数);Math.ceil(1.2)→2.0 -
Math.rint(double)向最近的偶数取整(IEEE 754 规则),Math.rint(2.5)和Math.rint(3.5)都返回2.0和4.0
常见错误:用 round 处理金额四舍五入——它返回 long,且对负数行为不符合财务习惯;应改用 BigDecimal 或手动加 0.5 再 floor。
开方、幂运算和对数:别直接用 Math.pow(x, 0.5) 求平方根
Math.sqrt(double) 是专用优化实现,比 Math.pow(x, 0.5) 更快、更准,且对边界值(如 Double.POSITIVE_INFINITY、0.0)行为明确。
立即学习“Java免费学习笔记(深入)”;
-
Math.sqrt(-1.0)返回NaN;Math.pow(-1.0, 0.5)同样是NaN,但性能差约 2–3 倍 -
Math.log(double)是自然对数(ln),不是常用对数(log₁₀);要算 log₁₀,用Math.log10(double),它在 JDK 8+ 中专为精度和性能优化过 -
Math.pow(0.0, 0.0)返回1.0(按 IEEE 定义),但Math.pow(0.0, -1.0)抛ArithmeticException(实际是返回Infinity,不抛异常;JVM 实现保证该行为)
三角函数单位是弧度,不是角度——转换漏掉 toRadians 就全错了
所有三角方法(sin、cos、tan、asin 等)只认弧度。传入角度值会得到完全错误的结果,而且不易被测试覆盖到。
- 正确写法:
Math.sin(Math.toRadians(30))→ ≈ 0.5;错写成Math.sin(30)→ ≈ -0.988(30 弧度 ≈ 1718°) -
Math.toDegrees(double)和Math.toRadians(double)是轻量级乘法封装(分别乘180/π和π/180),无精度损失,可放心用 - 反三角函数(如
Math.asin(0.5))返回弧度,记得用toDegrees转回来,否则日志里看到的是 “0.5236”,不是 “30”
生成随机数:别再用 Math.random() 做安全或并发场景
Math.random() 返回 [0.0, 1.0) 的 double,底层复用单个 java.util.Random 实例,是线程安全但有竞争;它不满足密码学随机性要求,也不支持流式生成。
- 普通场景够用,比如
(int)(Math.random() * 100)生成 [0, 99] 整数 - 高并发下性能瓶颈明显——多个线程争抢同一
Random实例的种子更新锁 - 替代方案:
ThreadLocalRandom.current().nextInt(100)(推荐)、或new Random().nextInt(100)(避免复用实例) - 需要加密安全随机数?必须用
SecureRandom,Math.random()绝对不行
最易被忽略的一点:所有 Math 方法都是 static 且 final,无法 mock——单元测试中若逻辑强依赖这些方法(比如根据 sin 输出做分支判断),得抽离成可注入的策略接口,而不是硬编码调用。









