Java 中处理超出基本数据类型范围的超大整数 / 超大小数,Java 提供了专门的java.math包来解决该问题,核心是两个类:BigInteger(超大整数)、BigDecimal(超大小数),下面从核心用法、场景对比、实战案例到避坑技巧全面讲解。
一、核心类基础认知
✅ 1. BigInteger 类(超大整数处理)
- 作用:处理任意长度、无精度丢失的整数,突破
long(最大 9223372036854775807)的取值上限 / 下限。 - 适用场景:超大整数运算(密码学、高精度计数、大数幂运算等)。
- 核心特点:不可变类(所有运算都会返回新对象,原对象不修改)、支持所有整数运算 + 取模 / 素数检测 / 进制转换等特殊操作。
✅ 2. BigDecimal 类(超大小数 / 高精度小数处理)
- 作用:处理任意精度的十进制小数,彻底解决
float/double的精度丢失问题(如0.1+0.2≠0.3)。 - 适用场景:金融计算、金额结算、科学计算、高精度小数运算等(必须用此类型,禁止用浮点型)。
- 核心特点:不可变类、支持精准小数运算、可自定义舍入模式、控制小数精度。
✅ 3. 与基本数据类型的核心区别
| 类型 | 取值范围 | 精度问题 | 适用场景 |
|---|---|---|---|
| byte/int/long | 固定有限范围 | 无(整数) | 常规小数值整数运算 |
| float/double | 范围大 | 有(浮点丢失) | 非精准的科学计算 |
| BigInteger | 无限制 | 无 | 超大整数精准运算 |
| BigDecimal | 无限制 | 无 | 小数 / 金额精准运算 |
二、BigInteger 完整使用教程
1. 对象创建(3 种常用方式)
BigInteger不能直接用赋值号创建,必须通过构造方法或静态方法初始化,核心方式如下:
import java.math.BigInteger; public class BigIntegerDemo { public static void main(String[] args) { // 方式1:字符串构造(最常用,支持超大数值)✅ 推荐 BigInteger big1 = new BigInteger("123456789012345678901234567890"); // 方式2:基本类型转换(int/long) BigInteger big2 = BigInteger.valueOf(100L); // 方式3:特殊常量(0、1、10,直接调用,性能更高) BigInteger zero = BigInteger.ZERO; BigInteger one = BigInteger.ONE; BigInteger ten = BigInteger.TEN; } }2. 核心运算方法(加减乘除 / 取模 / 幂等)
BigInteger不支持+、-、*、/运算符,必须调用类内封装的方法,所有方法返回新的 BigInteger 对象(原对象不变):
public static void main(String[] args) { BigInteger a = new BigInteger("1000000000000000000"); BigInteger b = new BigInteger("2000000000000000000"); // 1. 加法:a + b BigInteger add = a.add(b); // 2. 减法:a - b BigInteger sub = a.subtract(b); // 3. 乘法:a * b BigInteger mul = a.multiply(b); // 4. 除法:a / b(整除,无余数) BigInteger div = b.divide(a); // 5. 取模:a % b BigInteger mod = a.mod(b); // 6. 幂运算:a^3(a的3次方) BigInteger pow = a.pow(3); // 7. 绝对值 BigInteger abs = new BigInteger("-999").abs(); // 8. 比较大小(返回0相等,1>a大,-1>a小) int compare = a.compareTo(b); System.out.println("加法结果:" + add); System.out.println("幂运算结果:" + pow); }3. 常用特殊操作
BigInteger 内置了大量实用工具方法,满足大数场景的特殊需求:
public static void main(String[] args) { BigInteger num = new BigInteger("123456"); BigInteger target = new BigInteger("7"); // 1. 进制转换:10进制 → 2进制/16进制 String binary = num.toString(2); // 二进制 String hex = num.toString(16); // 十六进制 // 2. 最大公约数(GCD) BigInteger gcd = num.gcd(target); // 3. 素数检测(isProbablePrime(确定性),参数越大越精准,一般传50即可) boolean isPrime = new BigInteger("9973").isProbablePrime(50); // 4. 取反(相反数) BigInteger negate = num.negate(); System.out.println("10进制转2进制:" + binary); System.out.println("是否为素数:" + isPrime); }三、BigDecimal 完整使用教程(重点,金融必备)
✅ 核心前置知识(必看)
- 禁止用
double构造 BigDecimal:new BigDecimal(0.1)会得到0.10000000000000000555...,因为double本身存在精度丢失; - 推荐用「字符串构造」:
new BigDecimal("0.1")才能得到精准的0.1; - 舍入模式必须指定:除法 / 保留小数时,若无法整除,必须显式指定舍入模式,否则会抛出
ArithmeticException; - 不可变性:运算后返回新对象,原对象不修改。
1. 对象创建(3 种方式,区分优劣)
import java.math.BigDecimal; public class BigDecimalDemo { public static void main(String[] args) { // ❌ 错误方式:double构造,存在精度丢失 BigDecimal bad = new BigDecimal(0.1); // ✅ 推荐方式1:字符串构造(精准,无丢失) BigDecimal good1 = new BigDecimal("0.1"); // ✅ 推荐方式2:基本类型转换(int/long,无精度问题) BigDecimal good2 = BigDecimal.valueOf(100); // 等价于 new BigDecimal("100") // ✅ 推荐方式3:特殊常量 BigDecimal zero = BigDecimal.ZERO; BigDecimal one = BigDecimal.ONE; BigDecimal ten = BigDecimal.TEN; System.out.println("错误构造:" + bad); // 输出:0.1000000000000000055511151231257827021181583404541015625 System.out.println("正确构造:" + good1); // 输出:0.1 } }2. 核心运算方法(加减乘除)
同样不支持运算符,需调用封装方法,除法必须指定舍入模式:
public static void main(String[] args) { BigDecimal a = new BigDecimal("0.1"); BigDecimal b = new BigDecimal("0.2"); BigDecimal c = new BigDecimal("3"); // 1. 加法:0.1 + 0.2 = 0.3 ✅ 精准 BigDecimal add = a.add(b); // 2. 减法:0.2 - 0.1 = 0.1 BigDecimal sub = b.subtract(a); // 3. 乘法:0.1 * 0.2 = 0.02 BigDecimal mul = a.multiply(b); // 4. 除法:必须指定【舍入模式】,示例:1 ÷ 3 保留2位小数 BigDecimal div = BigDecimal.ONE.divide(c, 2, BigDecimal.ROUND_HALF_UP); System.out.println("0.1+0.2=" + add); // 输出:0.3 System.out.println("1÷3=" + div); // 输出:0.33 }3. 关键核心:舍入模式(常用 6 种)
舍入模式是 BigDecimal 的重中之重,决定了小数的取舍规则,金融场景优先用ROUND_HALF_UP(四舍五入),所有舍入模式均为BigDecimal的静态常量:
| 舍入模式常量 | 含义 | 示例(保留 2 位) |
|---|---|---|
| ROUND_HALF_UP ✅(推荐) | 四舍五入(银行家常用) | 2.346 → 2.35 |
| ROUND_UP | 向上进 1(远离 0) | 2.341 → 2.35 |
| ROUND_DOWN | 向下截断(靠近 0) | 2.349 → 2.34 |
| ROUND_HALF_DOWN | 五舍六入 | 2.345 → 2.34;2.346→2.35 |
| ROUND_CEILING | 向上取整(正无穷方向) | -2.34 → -2.34;2.34→2.35 |
| ROUND_FLOOR | 向下取整(负无穷方向) | -2.34 → -2.35;2.34→2.34 |
4. 高频实用操作(格式化 / 精度控制 / 比较)
(1)设置小数精度(保留指定位数,指定舍入模式)
// 保留2位小数,四舍五入 BigDecimal num = new BigDecimal("123.4567"); BigDecimal result = num.setScale(2, BigDecimal.ROUND_HALF_UP); System.out.println(result); // 输出:123.46(2)比较大小(必须用compareTo,禁止用equals)
equals:既比较值,又比较精度(0.1和0.10判定为不相等);compareTo:仅比较数值大小(推荐,返回值规则同 BigInteger)。
public static void main(String[] args) { BigDecimal d1 = new BigDecimal("0.1"); BigDecimal d2 = new BigDecimal("0.10"); // ❌ 错误:equals比较精度,返回false System.out.println(d1.equals(d2)); // false // ✅ 正确:compareTo仅比较数值,返回0(相等) System.out.println(d1.compareTo(d2) == 0); // true // 大于/小于判断 boolean gt = new BigDecimal("1.2").compareTo(new BigDecimal("1.1")) > 0; // true boolean lt = new BigDecimal("1.2").compareTo(new BigDecimal("1.3")) < 0; // true }(3)转基本类型(int/long/double)
BigDecimal big = new BigDecimal("100.99"); int intVal = big.intValue(); // 转int(截断小数)→ 100 long longVal = big.longValue(); // 转long →100 double doubleVal = big.doubleValue(); // 转double(可能丢失精度)→100.99四、BigInteger vs BigDecimal 核心区别(选型依据)
| 维度 | BigInteger | BigDecimal |
|---|---|---|
| 处理数据类型 | 纯整数(无小数) | 整数 + 小数(任意精度) |
| 核心优势 | 超大整数无限制运算 | 精准小数运算、解决浮点丢失 |
| 关键参数 | 无精度参数 | 需指定精度+舍入模式 |
| 核心场景 | 密码学、大数幂运算、进制转换 | 金融金额、高精度小数计算 |
| 特殊能力 | 素数检测、最大公约数 | 小数格式化、精度控制 |
✅选型口诀:
- 只算整数,且数值超
long→ 用BigInteger; - 涉及小数 / 金额 / 精准浮点 → 必用
BigDecimal; - 常规小数值整数 → 直接用
int/long。
五、常见坑点 & 避坑指南(必看)
❌ 坑 1:用double构造 BigDecimal
→ ✅ 解决:统一用字符串构造new BigDecimal("xxx")。
❌ 坑 2:BigDecimal 除法未指定舍入模式
→ ✅ 解决:除法必须传 3 个参数divide(除数, 保留位数, 舍入模式)。
❌ 坑 3:用equals比较 BigDecimal 大小
→ ✅ 解决:用compareTo方法比较,a.compareTo(b) == 0表示相等。
❌ 坑 4:忽略大数的不可变性,直接赋值运算结果
→ ✅ 解决:大数运算后必须接收返回值,如BigInteger c = a.add(b),而非直接a.add(b)。
❌ 坑 5:过度使用大数类,常规场景用 BigInteger/BigDecimal
→ ✅ 解决:int/long/float/double能满足的场景,优先用基本类型(性能更高)。
六、实战案例(2 个高频场景)
案例 1:超大整数幂运算(计算 100^20)
BigInteger base = BigInteger.valueOf(100); BigInteger result = base.pow(20); System.out.println("100^20 = " + result); // 输出:10000000000000000000000000000000000000000000000000案例 2:金融金额计算(订单结算:原价 - 折扣 + 税费,保留 2 位小数)
public static void main(String[] args) { // 订单原价、折扣、税费(均用字符串构造) BigDecimal price = new BigDecimal("999.99"); BigDecimal discount = new BigDecimal("50.5"); BigDecimal tax = new BigDecimal("23.68"); // 计算最终金额:原价 - 折扣 + 税费,保留2位小数,四舍五入 BigDecimal finalPrice = price.subtract(discount).add(tax) .setScale(2, BigDecimal.ROUND_HALF_UP); System.out.println("最终订单金额:¥" + finalPrice); // 输出:¥973.17 }总结
- Java 大数处理依赖
java.math包的BigInteger(超大整数)和BigDecimal(高精度小数); - 两者均为不可变类,运算后需接收返回值,不支持基础运算符;
- BigDecimal 是金融开发必备,核心是「字符串构造」+「指定舍入模式」;
- 大数类虽能解决精度 / 范围问题,但性能低于基本类型,按需使用;
- 核心避坑:BigDecimal 不用 double 构造、除法指定舍入模式、用 compareTo 比较大小。