【Java基础系列】BigDecimal入门

一.基本介绍

1.什么是 BigDecimal?

BigDecimal 是 Java 中的一个类,用于表示任意精度的十进制数。它属于 java.math 包,并提供了高精度的浮点数运算。与基本数据类型的浮点数(如 floatdouble)不同,BigDecimal 可以表示精确的小数,并且不会出现舍入误差。

2.BigDecimal 特点?

主要的特点包括:

  1. 任意精度: BigDecimal 可以处理非常大或非常小的数字,而不会失去精度。这对于需要精确计算货币、税收等金融领域的数据非常重要。

  2. 不受二进制浮点数表示误差的影响: 由于二进制浮点数表示法的限制,基本数据类型的浮点数可能会导致舍入误差。BigDecimal 使用基于十进制的表示,避免了这种误差。

  3. 支持精确的算术运算: BigDecimal 提供了一系列的算术运算方法,如加法、减法、乘法和除法,这些运算可以保持高精度。

  4. 不可变性: BigDecimal 对象是不可变的,一旦创建,就不能被修改。这有助于确保线程安全性。

  5. 丰富的方法: BigDecimal 提供了许多用于比较、取整、取余等操作的方法。

3.使用简介

以下是一个简单的示例,演示如何使用 BigDecimal 进行精确计算:

import java.math.BigDecimal;

public class BigDecimalExample {
    public static void main(String[] args) {
        BigDecimal num1 = new BigDecimal("10.5");
        BigDecimal num2 = new BigDecimal("2.3");

        // 加法
        BigDecimal sum = num1.add(num2);
        System.out.println("Sum: " + sum);

        // 减法
        BigDecimal difference = num1.subtract(num2);
        System.out.println("Difference: " + difference);

        // 乘法
        BigDecimal product = num1.multiply(num2);
        System.out.println("Product: " + product);

        // 除法,指定保留小数位数和舍入模式
        BigDecimal quotient = num1.divide(num2, 2, BigDecimal.ROUND_HALF_UP);
        System.out.println("Quotient: " + quotient);
    }
}

在这个示例中,BigDecimal 被用于执行精确的加法、减法、乘法和除法操作,并且可以通过指定保留小数位数和舍入模式来控制除法的结果。

二.使用简介

1.求和

求和

BigDecimal sum = Arrays.stream(bdArray).reduce(BigDecimal.ZERO, (p, q) -> p.add(q));
BigDecimal sum = list.stream().map(Person::getWeight)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);

2.自定义求和

自定义求和

BigDecimal sum = map.values().stream().reduce(BigDecimal.ZERO, Utility::addWeight);
import java.math.BigDecimal;
public class Utility {
	public static BigDecimal addWeight(BigDecimal w1, BigDecimal w2) {
		return w1.add(w2);
	}
}

3.小数计算

小数

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
public class BigDecimalSumUsingList {
	public static void main(String[] args) {
		Person p1 = new Person("AAA", new BigDecimal("45.23"));
		Person p2 = new Person("BBB", new BigDecimal("55.43"));
		Person p3 = new Person("CCC", new BigDecimal("65.21"));
		Person p4 = new Person("DDD", new BigDecimal("35.73"));
		List<Person> list = Arrays.asList(p1, p2, p3, p4);
		BigDecimal sum = list.stream().map(Person::getWeight)
		                     .reduce(BigDecimal.ZERO, BigDecimal::add);
		System.out.println(sum);

		sum = list.stream().map(p -> p.getWeight())
                .reduce(BigDecimal.ZERO, (b1, b2) -> b1.add(b2));
		System.out.println(sum);

		sum = list.stream().map(Person::getWeight)
                .reduce(BigDecimal.ZERO, Utility::addWeight);
		System.out.println(sum);

	}
}

BigDecimal求和

BigDecimal sum = products.stream()
                .map(Product::getPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

先相乘再累加:

 final BigDecimal mgmtPrmAmt = value.stream()
                            .map(product -> product.getMgmtPrmAmt().multiply(new BigDecimal(product.getSalQty())))
                            .reduce(BigDecimal.ZERO, BigDecimal::add);

4.加减乘除

public BigDecimal add(BigDecimal value);  //加
public BigDecimal subtract(BigDecimal value);//减
public BigDecimal multiply(BigDecimal value);  //乘
public BigDecimal divide(BigDecimal value); //除

5.除法细节

RoundingMode类型:

  • ROUND_HALF_UP:根据保留数字后一位>=5 进行四舍五入
  • ROUND_UP:不管保留数字后面是大是小(0 除外)都会进 1
  • ROUND_DOWN:保留设置数字,后面所有直接去除
  • ROUND_HALF_DOWN:跟 ROUND_HALF_UP 差别仅在于 0.5 时会向下取整
  • ROUND_HALF_EVEN:取最近的偶数
  • ROUND_UNNECESSARY:不需要取整,如果存在小数位,就抛 ArithmeticException 异常
  • ROUND_CEILING:如果 BigDecimal 是正的,则做 ROUND_UP 操作;如果为负,则做 ROUND_DOWN 操作 (一句话:取附近较大的整数)
  • ROUND_FLOOR: 如果 BigDecimal 是正的,则做 ROUND_DOWN 操作;如果为负,则做 ROUND_UP 操作(一句话:取附近较小的整数)

BigDecimal 的 divide 方法是用于执行除法运算的,其语法如下:

#语法
public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode)

 #举例
 BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP);

其中,参数说明如下:

  • divisor:被除数,即要将当前 BigDecimal 对象除以的数。
  • scale:表示除法运算的结果要保留的小数位数。
  • roundingMode:表示舍入模式,用于在执行除法运算时确定如何舍入结果。

该方法返回一个 BigDecimal 对象,表示除法运算的结果。

import java.math.BigDecimal;
/**
 * @author : qinyingjie
 * @version : 2.2.0
 * @date : 2022/10/5 12:27
 */
class Scratch {
    public static void main(String[] args) {
        //Java中BigDecimal取整方法
        BigDecimal bd = new BigDecimal("12.1");
        long l1 = bd.setScale(0, BigDecimal.ROUND_UP).longValue(); // 向上取整
        long l2 = bd.setScale(0, BigDecimal.ROUND_DOWN).longValue(); // 向下取整
        System.out.println(l1);
        System.out.println(l2);
    }
}

要将 a 除以 b,并将结果保留 2 位小数,可以使用如下代码:

BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");
BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP);
System.out.println(result);

在上述代码中,RoundingMode.HALF_UP 表示使用“四舍五入”方式将结果舍入到 2 位小数。

需要注意的是,如果除数为 0,则会抛出 ArithmeticException 异常。另外,如果计算结果超出了 BigDecimal 能表示的范围,则会抛出 ArithmeticException 异常。因此,在使用 BigDecimal 进行除法运算时,需要对这些异常进行适当的处理。

6.BigDecimal 与 0 比较

BigDecimal 如何判断是否大于 0、小于 0 和等于 0

if (number.compareTo(BigDecimal.ZERO) == 0) {
    System.out.println("BigDecimal对象等于0");
} else {
    System.out.println("BigDecimal对象不等于0");
}

7.保留 4 位小数

取最大值并保留 4 位小数,使用的方法是一个数除以 1 等于它本身

max.setTotalSalQtyStoreRate(new BigDecimal(result.stream().mapToDouble(item -> Objects.nonNull(item.getTotalSalQtyStoreRate()) ? item.getTotalSalQtyStoreRate().doubleValue() : 0).max().getAsDouble())
                .divide(new BigDecimal(1), 4, BigDecimal.ROUND_DOWN));

8.注意点

注意点:

  1. 小数先转为 String,不然会出现精度错误
  2. 比较用 compareTo,并且比较 0,用 BigDecimal.ZERO
  3. 除法时要确定保留小数的位数,不然有可能出现除不尽的情况
  4. 如果传入的字符串是一个非法的数值(null、字母、空),NumberFormatException 异常,
  5. 非空校验

BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)

roundingMode 为四舍五入的规则模型,用常量 int 来表示

你可能感兴趣的:(s0,常用工具,java,开发语言)