Java标准库无gcd函数,需手写;推荐循环版(安全高效),递归版有栈溢出风险,BigInteger.gcd仅适用于大数场景。

Java里用gcd函数前得自己写?标准库真没提供
Java标准库(包括java.lang.Math和java.util)确实没有内置的gcd函数。JDK 1.8+ 的BigInteger类倒是有gcd方法,但只接受BigInteger类型,对int或long要先包装,有额外开销,不推荐日常使用。
所以实际项目中,99%的情况是手写——核心就两个实现:递归版和循环版,都基于欧几里得算法(辗转相除法)。
递归实现gcd:简洁但要注意栈溢出风险
递归写法最贴近数学定义,代码短,可读性强,但容易忽略边界和深度问题。
- 必须处理负数:
gcd(a, b) == gcd(|a|, |b|),否则取模结果可能为负,导致无限递归 - 零值要提前返回:
gcd(a, 0) == |a|,否则gcd(0, 0)会陷入gcd(0, 0 % 0)——抛ArithmeticException: / by zero - 对极大数(比如接近
Long.MAX_VALUE的两个质数)递归深度可能超千层,触发StackOverflowError
示例(int版):
立即学习“Java免费学习笔记(深入)”;
public static int gcd(int a, int b) {
a = Math.abs(a);
b = Math.abs(b);
if (b == 0) return a;
return gcd(b, a % b);
}
循环实现gcd:更安全,性能略优,推荐生产用
循环版本避免了函数调用开销和栈风险,逻辑清晰,适合所有整数范围,是多数开源库(如Apache Commons Math)采用的方式。
- 同样需先取绝对值,否则
-12 % 5 == -2,后续计算会错乱 - 用
while (b != 0)比do-while更直观,也避免一次冗余迭代 - 对
long类型只需把参数和变量类型改掉,无其他改动;但注意Math.abs(Long.MIN_VALUE)会溢出为自身(仍是负数),需特殊处理
示例(long安全版):
public static long gcd(long a, long b) {
a = a == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(a);
b = b == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(b);
while (b != 0) {
long temp = b;
b = a % b;
a = temp;
}
return a;
}
别忘了BigInteger.gcd的适用场景和代价
当输入已经是BigInteger,或者数值可能超long范围时,直接用BigInteger.gcd最省心,它内部就是优化过的循环实现,且正确处理符号和零。
- 不要为了调用它而把
int转成BigInteger再转回——创建对象开销大,GC压力明显 -
BigInteger.gcd返回非负值,行为与手写一致 - 如果频繁计算小整数
gcd,用BigInteger反而慢3–5倍(实测JDK 17)
示例(仅限真正需要大数时):
BigInteger a = BigInteger.valueOf(123456789L); BigInteger b = BigInteger.valueOf(987654321L); BigInteger result = a.gcd(b); // 返回 BigInteger
递归写法看着漂亮,但上线前最好换成循环版;BigInteger.gcd不是银弹,别让它出现在热点路径里。最大公约数本身简单,但负数、零、溢出、类型转换这四点,漏一个就在线上返工。










