BigDecimal使用小结

工作总结

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---------------------------

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值