Java阶乘需用Math.multiplyExact()主动捕获溢出,避免静默绕回;n≤20可用long安全计算,超限应改用BigInteger,不可混用。

Java 中不能直接用 Math.multiplyExact() 实现完整阶乘(如 21! 就会溢出 long),但可以借助它在每次乘法时主动捕获溢出,让阶乘计算“失败得明确、安全、可感知”,而不是静默错误。核心思路是:循环中每一步都用 multiplyExact 做乘法,一旦溢出就立即抛出 ArithmeticException,从而实现自动防御。
为什么不用普通乘法?
普通 * 运算对 int 或 long 溢出不报错,结果会绕回(比如 Integer.MAX_VALUE * 2 得到负数),阶乘结果完全不可信。而 Math.multiplyExact(a, b) 在乘积超出目标类型范围时,**立刻抛出异常**,这是防御性编程的关键工具。
用 long 实现带溢出检查的阶乘
以下是一个安全、清晰的阶乘方法,适用于中小规模输入(n ≤ 20 对 long 是安全的):
说明:从 1 开始累乘,每次调用 Math.multiplyExact(result, i);若任意一步溢出,方法立即终止并抛出异常,调用方可以捕获处理。
立即学习“Java免费学习笔记(深入)”;
建议:
你是 TypeScript 项目架构专家,专注于脚手架搭建生产就绪的 Node.js 和前端应用。生成包含现代工具链(pnpm、Vite、Next.js)、类型
- 输入校验:
n 直接抛 <code>IllegalArgumentException - 边界特例:
n == 0 || n == 1直接返回 1(避免无谓调用) - 使用
long而非int,支持更大范围(最大安全值为 20! = 2,432,902,008,176,640,000)
捕获溢出并友好提示
调用方应主动处理异常,而不是放任崩溃。例如:
说明:不是把异常往上扔,而是转成业务友好的信息,比如告诉用户“输入值过大,已超过 64 位整数表示范围”。
建议:
- 用
try-catch(ArithmeticException e)捕获溢出 - 记录日志或返回错误码/提示消息,避免暴露底层异常细节给终端用户
- 可结合输入值预判:若
n > 20,直接拒绝,不进入循环(提升效率)
需要更大范围?升级到 BigInteger
若必须支持任意大的 n(如 1000!),long 不够用,此时应改用 java.math.BigInteger。它天然无溢出问题,但代价是性能下降、代码稍重。
说明:BigInteger.multiply() 永远不会溢出,适合高精度场景;但不再需要 multiplyExact —— 因为它本就不适用。
建议:
- 明确区分场景:小数值用
long + multiplyExact(快且安全);大数值用BigInteger(稳且通用) - 不要混用:比如用
long算到一半再转BigInteger,逻辑复杂且易错 - 注意
BigInteger构造开销,循环内避免重复创建对象

















