multiply()
BigDecimal 类提供了 multiply(BigDecimal multiplicand) 方法来进行乘法运算。

方法签名
public BigDecimal multiply(BigDecimal multiplicand)
- 参数:
multiplicand(乘数) - 返回值:一个新的
BigDecimal对象,表示两个数相乘的结果。 - 重要:
BigDecimal的对象是不可变的(Immutable)。multiply()方法不会修改当前对象,而是返回一个新的BigDecimal对象作为结果。
基本用法示例
下面是一个最简单的乘法计算示例。
import java.math.BigDecimal;
public class BigDecimalMultiplicationExample {
public static void main(String[] args) {
// 创建两个 BigDecimal 对象
// 推荐使用 String 构造函数,因为它能精确表示十进制数
BigDecimal num1 = new BigDecimal("10.5");
BigDecimal num2 = new BigDecimal("2.0");
// 执行乘法运算
// num1.multiply(num2) 返回一个新的 BigDecimal 对象
BigDecimal result = num1.multiply(num2);
// 打印结果
System.out.println("计算结果: " + result); // 输出: 计算结果: 21.0
}
}
重要:舍入模式
当乘法运算的结果无法用有限的位数精确表示时(1 * 0.1),或者当你需要控制结果的精度时,就必须指定舍入模式。
BigDecimal 提供了另一个重载的 multiply() 方法,允许你指定舍入模式和精度。
方法签名
public BigDecimal multiply(BigDecimal multiplicand, MathContext mc)
multiplicand: 乘数mc: 一个MathContext对象,它包含了精度和舍入模式。
或者,更常用的方式是先设置 scale(小数位数)和舍入模式:

public BigDecimal multiply(BigDecimal multiplicand, RoundingMode roundingMode)
常用舍入模式
RoundingMode.HALF_UP:四舍五入(最常用)。RoundingMode.UP:远离零方向舍入(正数向上取整,负数向下取整)。RoundingMode.DOWN:向零方向舍入(截断)。RoundingMode.CEILING:向正无穷方向舍入。RoundingMode.FLOOR:向负无穷方向舍入。
示例:需要舍入的场景
假设我们要计算 99 * 0.1,期望结果保留两位小数。
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalRoundingExample {
public static void main(String[] args) {
BigDecimal price = new BigDecimal("19.99");
BigDecimal discountRate = new BigDecimal("0.1");
// 直接相乘,结果会有很多位小数
BigDecimal rawResult = price.multiply(discountRate);
System.out.println("原始结果: " + rawResult); // 输出: 原始结果: 1.999000000000000000000000000
// 方式一:使用 scale 和 RoundingMode
// 保留2位小数,使用四舍五入模式
BigDecimal roundedResult1 = rawResult.setScale(2, RoundingMode.HALF_UP);
System.out.println("四舍五入后: " + roundedResult1); // 输出: 四舍五入后: 2.00
// 方式二:在乘法运算时直接指定舍入(推荐)
// 这通常更高效,因为它可以在计算过程中就进行舍入
BigDecimal roundedResult2 = price.multiply(discountRate, RoundingMode.HALF_UP);
// 此时结果的小数位数是原始操作数小数位数的和,但数值已经舍入
// 为了确保精度,最好再调用一次 setScale
BigDecimal finalResult = roundedResult2.setScale(2, RoundingMode.HALF_UP);
System.out.println("乘法时舍入后: " + finalResult); // 输出: 乘法时舍入后: 2.00
}
}
链式调用
BigDecimal 的方法都返回新的对象,因此非常适合链式调用,这在进行复杂的连续计算时非常有用。
示例:计算商品总价(单价 数量 税率)
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalChainingExample {
public static void main(String[] args) {
BigDecimal price = new BigDecimal("100.50");
BigDecimal quantity = new BigDecimal("3");
BigDecimal taxRate = new BigDecimal("0.0825"); // 8.25% 的税率
// 链式调用
BigDecimal total = price.multiply(quantity)
.multiply(taxRate)
.setScale(2, RoundingMode.HALF_UP);
System.out.println("含税总价: " + total); // 输出: 含税总价: 24.86
}
}
最佳实践和注意事项
-
始终使用
String构造函数 避免使用double或float来创建BigDecimal,因为它们本身就存在精度问题。new BigDecimal(0.1)会得到1000000000000000055511151231257827021181583404541015625,这不是你想要的。
(图片来源网络,侵删)// 错误方式 BigDecimal bad = new BigDecimal(0.1); // 正确方式 BigDecimal good = new BigDecimal("0.1"); -
避免使用
equals()方法equals()方法不仅比较数值,还会比较scale(小数位数),在大多数业务场景中,我们只关心数值是否相等。BigDecimal a = new BigDecimal("1.00"); BigDecimal b = new BigDecimal("1.000"); System.out.println(a.equals(b)); // 输出: false,因为 scale 不同 (2 vs 3) // 应该使用 compareTo() System.out.println(a.compareTo(b) == 0); // 输出: true,只比较数值 -
优先使用
compareTo()进行比较compareTo()是比较BigDecimal数值大小的标准方法,它返回 -1, 0, 或 1,分别表示小于、等于或大于。 -
为最终结果设置精度 在所有计算完成后,务必为最终用户可见的结果(如价格、金额)设置一个固定的
scale和合适的RoundingMode,这可以防止因中间计算产生的微小误差累积到最终结果中。
完整示例代码
下面是一个综合了上述所有要点的完整示例。
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalBestPracticeExample {
public static void main(String[] args) {
// 1. 使用 String 构造函数
BigDecimal itemPrice = new BigDecimal("99.99");
BigDecimal quantity = new BigDecimal("2");
BigDecimal discountPercent = new BigDecimal("0.15"); // 15% 折扣
BigDecimal taxRate = new BigDecimal("0.08"); // 8% 税
// 2. 计算小计 (单价 * 数量)
BigDecimal subtotal = itemPrice.multiply(quantity);
System.out.println("小计: " + subtotal); // 输出: 小计: 199.98
// 3. 计算折扣金额 (小计 * 折扣率)
BigDecimal discountAmount = subtotal.multiply(discountPercent);
// 在计算折扣金额时,可以四舍五入到分
discountAmount = discountAmount.setScale(2, RoundingMode.HALF_UP);
System.out.println("折扣金额: " + discountAmount); // 输出: 折扣金额: 30.00
// 4. 计算税前金额 (小计 - 折扣金额)
BigDecimal amountBeforeTax = subtotal.subtract(discountAmount);
System.out.println("税前金额: " + amountBeforeTax); // 输出: 税前金额: 169.98
// 5. 计算税费 (税前金额 * 税率)
BigDecimal tax = amountBeforeTax.multiply(taxRate);
// 税费也需要四舍五入到分
tax = tax.setScale(2, RoundingMode.HALF_UP);
System.out.println("税费: " + tax); // 输出: 税费: 13.60
// 6. 计算最终总价 (税前金额 + 税费)
BigDecimal total = amountBeforeTax.add(tax);
// 最终总价必须四舍五入到分,确保精度
total = total.setScale(2, RoundingMode.HALF_UP);
System.out.println("最终总价: " + total); // 输出: 最终总价: 183.58
// 7. 比较示例
BigDecimal price1 = new BigDecimal("183.580");
BigDecimal price2 = new BigDecimal("183.58");
// 使用 equals() 会失败
System.out.println("使用 equals 比较: " + price1.equals(price2)); // false
// 使用 compareTo() 会成功
System.out.println("使用 compareTo 比较: " + (price1.compareTo(price2) == 0)); // true
}
}
| 操作 | 方法 | 描述 | 示例 |
|---|---|---|---|
| 基本乘法 | multiply(BigDecimal) |
精确相乘,返回新对象。 | num1.multiply(num2) |
| 带舍入乘法 | multiply(BigDecimal, RoundingMode) |
相乘并应用舍入模式。 | num1.multiply(num2, RoundingMode.HALF_UP) |
| 设置精度 | setScale(int, RoundingMode) |
设置小数位数和舍入模式。 | result.setScale(2, RoundingMode.HALF_UP) |
| 比较 | compareTo(BigDecimal) |
比较两个数值大小。 | num1.compareTo(num2) == 0 |
| 构造 | new BigDecimal(String) |
推荐,精确构造。 | new BigDecimal("0.1") |
掌握了这些要点,你就可以在 Java 中安全、精确地进行各种高精度的乘法计算了。
