【Java基础系列】BigDecimal入门

一.基本介绍

1.什么是 BigDecimal?

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

2.BigDecimal 特点?

主要的特点包括:

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

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

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

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

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

3.使用简介

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

java 复制代码
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.求和

求和

java 复制代码
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.自定义求和

自定义求和

java 复制代码
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.小数计算

小数

java 复制代码
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求和

java 复制代码
BigDecimal sum = products.stream()
                .map(Product::getPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

先相乘再累加:

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

4.加减乘除

java 复制代码
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 方法是用于执行除法运算的,其语法如下:

apl 复制代码
#语法
public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode)

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

其中,参数说明如下:

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

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

java 复制代码
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 位小数,可以使用如下代码:

java 复制代码
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

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

7.保留 4 位小数

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

java 复制代码
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 来表示

相关推荐
喵叔哟12 分钟前
重构代码中引入外部方法和引入本地扩展的区别
java·开发语言·重构
尘浮生18 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
hopetomorrow32 分钟前
学习路之PHP--使用GROUP BY 发生错误 SELECT list is not in GROUP BY clause .......... 解决
开发语言·学习·php
不是二师兄的八戒42 分钟前
本地 PHP 和 Java 开发环境 Docker 化与配置开机自启
java·docker·php
小牛itbull42 分钟前
ReactPress vs VuePress vs WordPress
开发语言·javascript·reactpress
请叫我欧皇i1 小时前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
闲暇部落1 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
爱编程的小生1 小时前
Easyexcel(2-文件读取)
java·excel
GIS瞧葩菜1 小时前
局部修改3dtiles子模型的位置。
开发语言·javascript·ecmascript
chnming19871 小时前
STL关联式容器之set
开发语言·c++