Java BigDecimal使用指南
提起BigDecimal,相信大家都使用过,之所以总结这篇呢,是因为最近发现项目中使用的不是太规范,在某些场景下甚至出现代码抛出异常的情况,
所以就总结了这篇,希望大家在使用时,可以少踩一些坑。
1. 基本运算
1.1 加法
BigDecimal number1 = new BigDecimal("88.88");
BigDecimal number2 = new BigDecimal("11.12");
BigDecimal number3 = number1.add(number2);
System.out.println("number1 add number2 = " + number3);
输出结果:
number1 add number2 = 100.00
1.2 减法
BigDecimal number1 = new BigDecimal("88.88");
BigDecimal number2 = new BigDecimal("11.12");
BigDecimal number3 = number1.subtract(number2);
System.out.println("number1 subtract number2 = " + number3);
输出结果:
number1 subtract number2 = 77.76
1.3 乘法
BigDecimal number1 = new BigDecimal("88.88");
BigDecimal number2 = new BigDecimal("11.12");
BigDecimal number3 = number1.multiply(number2);
System.out.println("number1 multiply number2 = " + number3);
输出结果:
number1 multiply number2 = 988.3456
1.4 除法
BigDecimal number1 = new BigDecimal("88");
BigDecimal number2 = new BigDecimal("11");
BigDecimal number3 = number1.divide(number2);
System.out.println("number1 divide number2 = " + number3);
输出结果:
number1 divide number2 = 8
因为上面2个数可以整除,所以这么用没有问题,不过一但不能被整除,这么用就会有潜在的风险,会抛出java.lang.ArithmeticException异常,所以强烈建议像下面这样使用:
BigDecimal number1 = new BigDecimal("88.88");
BigDecimal number2 = new BigDecimal("11.12");
BigDecimal number3 = number1.divide(number2, 2, RoundingMode.HALF_UP);
System.out.println("number1 divide number2 = " + number3);
输出结果:
number1 divide number2 = 7.99
此时使用的divide()方法源码如下所示:
public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode) {
return divide(divisor, scale, roundingMode.oldMode);
}
这里的scale指的是要保留的小数位数,我们传的是2,即保留2位小数。
这里的roundingMode指的是舍入模式,我们这里传的是RoundingMode.HALF_UP,即经常使用的四舍五入模式。
1.5 保留小数位数
如果我们想对BigDecimal类型保留小数位数,可以使用setScale()方法,使用方法如下所示:
BigDecimal number1 = new BigDecimal("88.88");
BigDecimal number2 = new BigDecimal("11.12");
BigDecimal number3 = number1.multiply(number2);
System.out.println("number1 multiply number2 = " + number3);
// 保留3位小数,四舍五入
BigDecimal number4 = number3.setScale(3, RoundingMode.HALF_UP);
System.out.println("number3 setScale = " + number4);
输出结果:
number1 multiply number2 = 988.3456
number3 setScale = 988.346
1.6 比较大小
BigDecimal比较大小,可以使用compareTo()方法,使用方法如下所示:
BigDecimal number1 = new BigDecimal("88.88");
BigDecimal number2 = new BigDecimal("11.11");
BigDecimal number3 = new BigDecimal("99.99");
BigDecimal number4 = new BigDecimal("88.88");
System.out.println("number1 compareTo number2 = " + number1.compareTo(number2));
System.out.println("number1 compareTo number3 = " + number1.compareTo(number3));
System.out.println("number1 compareTo number4 = " + number1.compareTo(number4));
输出结果:
number1 compareTo number2 = 1
number1 compareTo number3 = -1
number1 compareTo number4 = 0
由输出结果可以看出:
当number1小于number2时,返回-1,
当number1等于number2时,返回0,
当number1大于number2时,返回1。
2. 踩坑总结
2.1 NullPointerException异常
在使用BigDecimal类型进行计算时,比如上面提到的加、减、乘、除、比较大小时,一定要保证参与计算的两个值不能为空,否则会抛出java.lang.NullPointerException异常。
比如下面的2段代码,都会抛出异常:
BigDecimal number1 = null;
BigDecimal number2 = new BigDecimal("11.12");
BigDecimal number3 = number1.add(number2);
System.out.println("number1 add number2 = " + number3);
BigDecimal number1 = new BigDecimal("88.88");
BigDecimal number2 = null;
BigDecimal number3 = number1.add(number2);
System.out.println("number1 add number2 = " + number3);
抛出的异常如下图所示:

2.2 ArithmeticException异常
一次在使用BigDecimal的divide方法时,抛出java.lang.ArithmeticException异常,错误代码如下所示:
// 含税金额
BigDecimal inclusiveTaxAmount = new BigDecimal("1000");
// 税率
BigDecimal taxRate = new BigDecimal("0.13");
// 不含税金额 = 含税金额 / (1+税率)
BigDecimal exclusiveTaxAmount = inclusiveTaxAmount.divide(BigDecimal.ONE.add(taxRate));
System.out.println(exclusiveTaxAmount);
运行时抛出以下异常:
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

报错原因是因为无法整除,导致结果是无限循环小数:

解决方案是指定下舍入模式,比如我们最常用的四舍五入模式:
// 不含税金额 = 含税金额 / (1+税率)
BigDecimal exclusiveTaxAmount = inclusiveTaxAmount.divide(BigDecimal.ONE.add(taxRate),RoundingMode.HALF_UP);
此时不再报错,输出结果为:
885
但这里我的需求是保留2位小数,四舍五入,因此代码应该是下面这样的:
// 不含税金额 = 含税金额 / (1+税率)
BigDecimal exclusiveTaxAmount = inclusiveTaxAmount.divide(BigDecimal.ONE.add(taxRate), 2, RoundingMode.HALF_UP);
此时的输出结果为:
884.96
如果你的IDEA装了阿里巴巴代码规范插件,如果不指定RoundingMode,会有下面这样的提示:

3. 使用规范
尽量不要在项目中使用new BigDecimal("0"),而是使用BigDecimal提供的常量BigDecimal.ZERO。
BigDecimal zero = BigDecimal.ZERO;
BigDecimal one = BigDecimal.ONE;
BigDecimal ten = BigDecimal.TEN;
Java BigDecimal使用指南的更多相关文章
- Java学习笔记(四)——google java编程风格指南(上)
[前面的话] 年后开始正式上班,计划着想做很多事情,但是总会有这样那样的打扰,不知道是自己要求太高还是自我的奋斗意识不够?接下来好好加油.好好学学技术,好好学习英语,好好学习做点自己喜欢的事情,趁着自 ...
- Java学习笔记(五)——google java编程风格指南(中)
[前面的话] 年后开始正式上班,计划着想做很多事情,但是总会有这样那样的打扰,不知道是自己要求太高还是自我的奋斗意识不够?接下来好好加油.好好学学技术,好好学习英语,好好学习做点自己喜欢的事情,趁着自 ...
- Java学习笔记(六)——google java编程风格指南(下)
[前面的话] 年后开始正式上班,计划着想做很多事情,但是总会有这样那样的打扰,不知道是自己要求太高还是自我的奋斗意识不够?接下来好好加油.好好学学技术,好好学习英语,好好学习做点自己喜欢的事情,趁着自 ...
- Java多线程初学者指南系列教程
转自:http://developer.51cto.com/art/200911/162925.htm 51cto 本系列来自NokiaGuy的“真的有外星人吗”博客,系列名称为<Java多线程 ...
- 【Todo】【读书笔记】Java多线程编程指南-设计模式篇
下了这本书<Java多线程编程指南-设计模式篇>, 还有另一本<JAVA多线程设计模式>,据说内容有重复,结合着看.
- Java工程师学习指南 完结篇
Java工程师学习指南 完结篇 先声明一点,文章里面不会详细到每一步怎么操作,只会提供大致的思路和方向,给大家以启发,如果真的要一步一步指导操作的话,那至少需要一本书的厚度啦. 因为笔者还只是一名在校 ...
- Java工程师学习指南 中级篇
Java工程师学习指南 中级篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我写的文章都是站 ...
- Java工程师学习指南 初级篇
Java工程师学习指南 初级篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我之前写的文章都 ...
- Java工程师学习指南 入门篇
Java工程师学习指南 入门篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我之前写的文章都 ...
随机推荐
- 11-21 logging 模块
默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志, 这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ER ...
- Python os.utime() 方法
概述 os.utime() 方法用于设置指定路径文件最后的修改和访问时间.高佣联盟 www.cgewang.com 在Unix,Windows中有效. 语法 utime()方法语法格式如下: os.u ...
- MB2-718 Certification: (Microsoft Dynamics 365 Customer Service) – Field Service, Customer Assets
Come from : https://neilparkhurst.com/2018/02/25/mb2-718-certification-microsoft-dynamics-365-custom ...
- 教你不编程快速解析 JSON 数据
JSON 是一种轻量级的,不受语言约束的数据存储格式,大部分编程语言都可以解析它,并且对编程人员也十分友好.我们在进行通讯/数据交互时,非常经常用到 JSON 格式. 但是,我们在进行数据存储的时候, ...
- 关于ORACLE索引的几种扫描方式
------------恢复内容开始------------ ------------恢复内容开始------------ 一条sql执行的效率因执行计划的差异而影响,经常说这条sql走索引了,那条s ...
- win10 64位 汇编环境
masm6或者masm5 下载. dosbox 下载安装 为何要用这个呢,因为 机子是64位的,dosbox 模拟32位的用来执行生成的exe文件 masm 安装好后,有个bin文件:个人建议将其设置 ...
- 12、Decorator 装饰器 模式 装饰起来美美哒 结构型设计模式
1.Decorator模式 装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰器模式(Decorator Pattern)允许向一个现 ...
- 基于Asp.net Core 3.1实现的Redis及MemoryCache缓存助手CacheHelper
这几天在面试,这个关于Redis缓存的博客一直没空写,今天总算有点时间了. 从很久很久之前,我就一直想学Redis了,反正看到各大招聘网上都要求Redis,不学就太落后了. 一开始我是按微软官网文档那 ...
- C#LeetCode刷题之#700-二叉搜索树中的搜索(Search in a Binary Search Tree)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4102 访问. 给定二叉搜索树(BST)的根节点和一个值. 你需要 ...
- 手把手mc开服教学(内置开服核心)
QQ交流群:1125669835 mc开服教程 首先我们需要下载一个开服核心,然后把服务器核心放在一个空文件夹里(这是我的开服核心) 然后再打开(感jio这是废话,要耐心等待......) 然后你会发 ...