biginteger构造时字符串必须trim且不能有前导零,否则抛numberformatexception;算术操作须用add()等方法而非运算符;比较应统一用compareto(),避免==或equals()陷阱。

BigInteger构造时字符串不能带空格或前导零
Java里BigInteger从字符串构造看似简单,但实际踩坑率极高。比如new BigInteger(" 123")或new BigInteger("00123")都会直接抛NumberFormatException——它不自动trim,也不支持八进制解析(除非显式指定进制)。
常见错误现象:读配置或解析JSON后拿到的数字字符串带空格、换行或BOM头,一构造就崩;或者前端传来的"000123"被当成非法格式。
- 务必先
str.trim()再传入构造函数 - 若需支持前导零,用
new BigInteger(str.trim(), 10)显式指定十进制,避免歧义 - 从文件/网络读取时,建议加一层校验:
if (str == null || str.trim().isEmpty()) throw new IllegalArgumentException(...)
加减乘除必须用方法调用,不能用+ - * /运算符
这是新手最常懵的地方:写a + b编译就报错,因为BigInteger是不可变对象,没有重载运算符。所有算术操作都得走add()、subtract()、multiply()、divide()这些方法。
使用场景集中在高精度计费、密码学计算、天文数值处理等不能丢精度的场合;一旦混用基本类型(如int)和BigInteger,容易误以为能自动转换。
立即学习“Java免费学习笔记(深入)”;
-
divide()遇到除不尽会直接抛ArithmeticException,不是返回小数——需要整除才用它;否则改用divideAndRemainder()或转BigDecimal - 链式调用安全但易写长:
a.multiply(b).add(c).subtract(d),注意括号优先级和中间结果是否可能为null(虽然BigInteger本身不会null,但变量可能) - 性能上,
multiply()比pow(2)快得多,别用pow()做位移类操作
compareTo()是唯一可靠的比较方式,==和equals()都危险
用==比较两个BigInteger几乎总是false,哪怕值相同——因为它是对象引用比较;equals()虽能比值,但要注意参数为null时返回false,不抛异常,容易掩盖逻辑缺陷。
真实调试中常见问题:条件判断写成if (x.equals(BigInteger.ONE)),结果x是null,整个判断静默失败;或者用if (x == BigInteger.ZERO),永远不进分支。
- 统一用
x.compareTo(BigInteger.ZERO) == 0判断是否为零 - 比较大小用
compareTo()返回值:-1(小于)、0(等于)、1(大于),别拆成多个equals()拼凑 - 如果确定非null,
equals()可用,但必须前置判空,或用Objects.equals(a, b)
toByteArray()和longValueExact()的隐式截断风险
toByteArray()返回的是二进制补码表示,不是简单的字节展开——负数会多一个高位字节;而longValueExact()在值超出long范围时直接抛异常,不是静默截断。这两点在线程间传递或序列化时最容易出错。
典型场景:把BigInteger存进Redis或写进Protobuf,用toByteArray()后没注意符号位,反序列化出来变号;或用longValue()替代longValueExact(),结果大数被悄悄变成负数。
- 跨系统传输优先用
toString()或encodeX509()(如果协议要求DER) - 必须转
long时,明确处理溢出:try { return x.longValueExact(); } catch (ArithmeticException e) { /* fallback */ } -
toByteArray()结果不要直接Arrays.toString()调试——看的是字节内容,不是数值,建议用String.format("0x%s", x.toString(16))辅助验证
真正麻烦的从来不是“怎么算”,而是“在哪算完之后怎么交出去”——序列化、比较、边界检查,每一步都藏着和基本类型不一样的契约。稍不注意,数值还在,语义已经偏了。










