概述
工作总结
BigDecimal使用小结
当业务涉及到大数的精确计算,比如钱或者重量等有小数点且要求一定精度的数值时,常常会使用BigDecimal类型定义该字段,这里列举了一些BigDecimal的常用用法
1).获取BigDecimal数值
1. 直接定义变量并赋值
BigDecimal money100 = new BigDecimal(100);
2. 直接获取常量值
//获取BigDecimal类型的0
BigDecimal money0 = BigDecimal.ZERO;
//获取BigDecimal类型的1
BigDecimal money1 = BigDecimal.ONE;
//获取BigDecimal类型的10
BigDecimal money10 = BigDecimal.TEN;
3. 其他类型的数值转BigDecimal
//new BigDecimal()会有精度问题,所以建议使用字符串去创建对象而不是浮点类型
//BigDecimal.valueOf()底层使用的就是用字符串去创建对象,确保精度不会丢失
//获取BigDecimal类型的整数
BigDecimal money11 = BigDecimal.valueOf(11);
//获取BigDecimal类型的浮点数
BigDecimal money1_1 = BigDecimal.valueOf(1.1);
2).常用BigDecimal函数
/**
* 四则运算
*/
//加-add():100+1
BigDecimal money101 = money100.add(money1);
//减-subtract():100-1
BigDecimal money99 = money100.subtract(money1);
//乘-multiply():10*1.1
BigDecimal money11 = money10.multiply(money1_1);
//整除-divide()(不整除时抛异常java.lang.ArithmeticException):99/11
BigDecimal money9 = money99.divide(money11);
//不整除-divide(BigDecimal divisor, int scale, int roundingMode):101/11
//divisor:除数 scale:保留小数位数 roundingMode:舍入策略
BigDecimal money9_18 = money101.divide(money11,2,ROUND_CEILING);
/**
* 数值转换
*/
//取余数-remainder():101/11
BigDecimal money2 = money101.remainder(money11);
//取反-negate():-1
BigDecimal money_1 = money1.negate();
//取绝对值-abs():|-1|
BigDecimal money_1_ = money_1.abs();
//保留小数位数-setScale(int scale, int roundingMode):四舍五入/五舍六入/...
BigDecimal money1_100 = money1_1.setScale(3, BigDecimal.ROUND_HALF_UP);
//将BigDecimal对象中的值转换成双精度数
double doubleMoney = money0.doubleValue();
//将BigDecimal对象中的值转换成单精度数
float floatMoney = money0.floatValue();
//将BigDecimal对象中的值转换成长整数
long longValue = money0.longValue();
//将BigDecimal对象中的值转换成整数
int intValue = money0.intValue();
//将BigDecimal对象中的值转换成字符串
//必要时,使用科学计数法
String str1 = money0.toString();
//不使用科学计数法
String str2 = money0.toPlainString();
//工程计算中经常使用的记录数字的方法,类似科学计数法,但要求是10的幂必须是3的倍数
String str3 = money0.toEngineeringString();
/**
* BigDecimal大小比较
* BigDecimal中equals方法的实现会比较两个数字的精度,而compareTo方法则只会比较数值的大小
*/
BigDecimal.valueOf(1.1)
// result = -1,表示小于; result = 0,表示等于; result = 1,表示大于
int result = BigDecimal.valueOf(1.1).compareTo(BigDecimal.valueOf(1.10));//0
boolean isEquales = BigDecimal.valueOf(1.1).equals(BigDecimal.valueOf(1.10));//false
/**
* BigDecimal舍入策略(枚举)
*/
//向1的方向舍入(即不论正负,保留精度最后一位+1):5.54->5.6 | 5.56->5.6 | -5.54->-5.6
BigDecimal.ROUND_UP
//向0方向舍入(即不论正负,保留精度最后一位+0):5.54->5.5 | 5.56->5.5 | -5.54->-5.5
BigDecimal.ROUND_DOWN
//向+∞方向舍入(即正数保留精度最后一位+1,负数保留精度最后一位+0):5.54->5.6 | -5.54->-5.5 -5.54->-5.6
BigDecimal.ROUND_CEILING
//向-∞方向舍入(即正数保留精度最后一位+0,负数保留精度最后一位+1):5.54->5.5 | -5.54->-5.6
BigDecimal.ROUND_FLOOR
//向(距离)最近的一边舍入,除非两边(的距离)是相等(即银行家舍入):5.54->5.5 | 5.56->5.6 | 5.55->5.6 | 5.45->5.4
//银行家舍入:四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一(即不论正负,保留精度最后一位是偶数+0,是奇数+1)
BigDecimal.ROUND_HALF_EVEN
//向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向下舍入(即四舍五入):1.55->1.5
BigDecimal.ROUND_HALF_DOWN
//向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向上舍入(即五舍六入):1.55->1.6
BigDecimal.ROUND_HALF_UP
//计算结果是精确的,不需要舍入模式
//如果在产生不精确结果的操作上指定了这种舍入模式,则会引发ArithmeticException
BigDecimal.ROUND_UNNECESSARY
3).通过validation注解校验BigDecimal入参
1.参数实体
@Data
public class BigDecimalValidationTestDTO {
/**
* @Digits 小数位校验
* @DecimalMin 最小值校验
* @DecimalMax 最大值校验
* @NotNull 非空校验
* BigDecimal 数字和字符格式都能识别
*
*/
@Digits(integer = 3, fraction=2, message = "资金格式错误")
@DecimalMin(value = "0.00", message = "资金最小值不能低于0.00元")
@DecimalMax(value = "10.00", message = "资金最大值不能高于10.00元")
@NotNull(message = "资金不可为空")
private BigDecimal money;
}
2.控制层接收器
@RestController
@RequestMapping("/test")
public class BigDecimalValidationTestController{
@PostMapping(value = "/method")
public BigDecimal bigDecimalValidationTestMethod(@RequestBody @Valid BigDecimalValidationTestDTO request) {
return request.getMoney();
}
}
4).利用Java8的流式方法计算bigDecimal
@Data
@ApiModel(description = "测试参数")
public class TestDTO {
@ApiModelProperty(value = "金额")
private BigDecimal amount;
}
public class DemoTest {
@Test
public void testTermRepeat() {
List<TestDTO> list = Lists.newArrryList();
//填充list...
//TestDTO集合中的金额累加
BigDecimal totalAmount = list.stream()
.map(TestDTO::getAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
5).使用总结
1.BigDecimal的性能比double和float差,在处理庞大或复杂的运算时尤为明显。故在需要精确的小数计算时再使用BigDecimal,一般精度的计算没必要使用BigDecimal。
2浮点类型的值创建对象的时候应该使用BigDecimal.valueOf(double value)而不是new BigDecimal(),因为后者会有精度问题,所以建议使用字符串去创建对象而不是浮点类型,BigDecimal.valueOf()底层使用的就是用字符串去创建对象,确保精度不会丢失。
3.BigDecimal都是不可变的(immutable)的,每进行一次四则运算都会产生一个新的对象,所以在做加减乘除运算时要记得要保存操作后的值。
4.BigDecimal并不代表无限精度,所以divide(BigDecimal divisor)方法只能计算整除,在非整除运算中出现无限循环小数时,就会抛异常:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result;解决方法是改用带精度的方法比如:divide(BigDecimal divisor, int scale)方法或divide(BigDecimal divisor, int scale, int roundingMode)方法
5.等值比较时建议用compareTo()方法而不是equals()方法,因为前者只比较数值大小,后者还会额外比较精度;
6.乘法满足交换律是一个常识,但是在计算机的世界里,会出现不满足乘法交换律的情况,所以BigDecimal的执行顺序不能调换;
------------------------TO-BE-CONTINUE---------------------------
最后
以上就是优秀长颈鹿为你收集整理的BigDecimal使用小结BigDecimal使用小结的全部内容,希望文章能够帮你解决BigDecimal使用小结BigDecimal使用小结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复