28.从零开始学springboot-详解金钱类BigDecimal

springboot中参数校验 在Spring Boot中,可通过 JSR 380规范注解(如@DecimalMin、@DecimalMax)结合 自定义注解 实现BigDecimal类型字段的大小校验。@Digits是JSR 380规范中的校验注解,用于限制数字类型(如BigDecimal、Integer、String)的整数位和小数位长度。需求:年龄字段(Integer)必须为整数,且整数位≤3(如99合法,1000或18.5非法)。适用场景:需自定义校验规则(如值必须为正数、非零,或动态范围)。 阅读详情

前言

作者最近开发项目, 需要用到java的金钱处理类BigDecimal.

为什么要BigDecimal而不用Float或Double

对此很多有和我一样,肯定有疑惑,一般的金钱用Double就行,怎么整出个BigDecimal类?why?

其实,这和计算机的设计有关,原因在于我们的计算机是二进制的。浮点数没有办法是用二进制进行精确表示。

计算机CPU表示浮点数由两个部分组成:指数和尾数,这样的表示方法一般都会失去一定的精确度,有些浮点数运算也会产生一定的误差。

Float和Double类型的主要设计目标是为了科学计算和工程计算。他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的。

然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合。

因此,Float和Double只能用來做科学计算或者是工程计算,在商业计算中我们要用java.math.BigDecimal

BigDecimal的初始化

BigDecimal提供了丰富的构造函数,可以通过int、long、double、String等来构造一个BigDecimal对象。
构造器描述

BigDecimal(int)       创建一个具有参数所指定整数值的对象。 
BigDecimal(double) 创建一个具有参数所指定双精度值的对象。 
BigDecimal(long)    创建一个具有参数所指定长整数值的对象。 
BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象

那么这几种不同的类型构造出的BigDecimal对象有区别么?
当然是有的.
我们做如下测试:

BigDecimal a = new BigDecimal(1.1);
BigDecimal b = BigDecimal.valueOf(1.1);
BigDecimal c = new BigDecimal("1.1");
System.out.println("a="+a);
System.out.println("b="+b);
System.out.println("c="+c);

结果

a=1.100000000000000088817841970012523233890533447265625
b=1.1
c=1.1

可以看出,Double类型的初始化显然是有问题的,为什么?

因为计算机01的方式对于十进制的0.1是无法精确表示的,所以对于Double数字只能接近表示,如果用这个Double来初始化BigDecimal的话就会出现问题。

我看看看对此现象的官方描述:

  1. 参数类型为Double的构造方法的结果有一定的不可预知性。有人可能认为在Java中写入newBigDecimal(0.1)所创建的BigDecimal正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法准确地表示为 Double(或者说对于该情况,不能表示为任何有限长度的二进制小数).这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值).

2 .另一方面,String 构造方法是完全可预知的:写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言,通常建议优先使用String构造方法。

但是,有时候我们不得不用Double来初始化BidDecimal,此时,我们请使用Double.toString(double)转成String,然后使用String构造方法,或使用BigDecimal的静态方法valueOf.

所以总结一下,推荐使用string类型来初始化BigDecimal
通常有如下三种方法

//方法一
BigDecimal bg1 = new BigDecimal("1.1");
//方法二
BigDecimal bg2 = new BigDecimal(Double.toString(1.1));
//方法三
BigDecimal bg3 = BigDecimal.valueOf(1.1);

BigDecimal.value(double val)方法为什么可以呢?
看看源码的实现:

public static BigDecimal valueOf(double val) {
  return new BigDecimal(Double.toString(val));
 }

BigDecimal的加减乘除

  • add(BigDecimal) 加法
  • subtract(BigDecimal) 减法
  • multiply(BigDecimal) 乘法
  • divide(BigDecimal) 除法
  • toString() 将BigDecimal对象的数值转换成字符串。
  • doubleValue() 将BigDecimal对象中的值以双精度数返回。
  • floatValue() 将BigDecimal对象中的值以单精度数返回。
  • longValue() 将BigDecimal对象中的值以长整数返回。
  • intValue() 将BigDecimal对象中的值以整数返回
  • abs() 绝对值
//加法
BigDecimal result1 = num1.add(num2);
BigDecimal result12 = num12.add(num22);
//减法
BigDecimal result2 = num1.subtract(num2);
BigDecimal result22 = num12.subtract(num22);
//乘法
BigDecimal result3 = num1.multiply(num2);
BigDecimal result32 = num12.multiply(num22);
//除法
BigDecimal result5 = num2.divide(num1,20,BigDecimal.ROUND_HALF_UP);
BigDecimal result52 = num22.divide(num12,20,BigDecimal.ROUND_HALF_UP);
//绝对值
BigDecimal result4 = num3.abs();
BigDecimal result42 = num32.abs();

这里有一点需要注意的是除法运算divide.
BigDecimal除法可能出现不能整除的情况,比如 4.5/1.3,这时会报错

java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

divide方法有两个重载的方法,

  • 两个参数的方法:
    divide(传入除数, 传入round的模式)

  • 三个参数的方法:
    divide(传入除数, 传入精度, 传入round的模式)

所以,为了避免除不尽的情况,我们需要传入精度参数

num1.divide(num2, 2, BigDecimal.ROUND_HALF_UP);

所以,如果用BigDecimal做除法的时候,一定要在divide方法中传递第二个参数,定义精确到小数点后几位,否则在不整除的情况下,结果是无限循环小数时,就会抛出以上异常。

ROUND的8种模式

  • ROUND_UP
    舍入远离零的舍入模式。
    在丢弃非零部分之前始终增加数字(始终对非零舍弃部分前面的数字加1)。
    注意,此舍入模式始终不会减少计算值的大小。

  • ROUND_DOWN
    接近零的舍入模式。
    在丢弃某部分之前始终不增加数字(从不对舍弃部分前面的数字加1,即截短)。
    注意,此舍入模式始终不会增加计算值的大小。

  • ROUND_CEILING
    接近正无穷大的舍入模式。
    如果 BigDecimal 为正,则舍入行为与 ROUND_UP 相同;
    如果为负,则舍入行为与 ROUND_DOWN 相同。
    注意,此舍入模式始终不会减少计算值。

  • ROUND_FLOOR
    接近负无穷大的舍入模式。
    如果 BigDecimal 为正,则舍入行为与 ROUND_DOWN 相同;
    如果为负,则舍入行为与 ROUND_UP 相同。
    注意,此舍入模式始终不会增加计算值。

  • ROUND_HALF_UP
    向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。
    如果舍弃部分 >= 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同。
    注意,这是我们大多数人在小学时就学过的舍入模式(四舍五入)。

  • ROUND_HALF_DOWN
    向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为上舍入的舍入模式。
    如果舍弃部分 > 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同(五舍六入)。

  • ROUND_HALF_EVEN
    向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。
    如果舍弃部分左边的数字为奇数,则舍入行为与 ROUND_HALF_UP 相同;
    如果为偶数,则舍入行为与 ROUND_HALF_DOWN 相同。
    注意,在重复进行一系列计算时,此舍入模式可以将累加错误减到最小。
    此舍入模式也称为“银行家舍入法”,主要在美国使用。四舍六入,五分两种情况。
    如果前一位为奇数,则入位,否则舍去。
    以下例子为保留小数点1位,那么这种舍入方式下的结果。
    1.15>1.2 1.25>1.2

  • ROUND_UNNECESSARY
    断言请求的操作具有精确的结果,因此不需要舍入。
    如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException。

请关注我的订阅号

订阅号.png

Jackson 配置 Bigdecimal 序列化 使用 jackson 配置 BigDecimal 序列化,欢迎阅读斧正。 阅读详情

相关推荐

Springboot 处理BigDecimal 数据科学计数格式,展示E+8的问题

Springboot 处理BigDecimal 数据科学计数格式,展示E+8的问题

默默不代表沉默 5281

SpringBoot--解决BigDecimal传到前端后精度丢失的问题

本文用示例介绍SpringBoot如何解决BigDecimal传到前端后精度丢失问题。

IT利刃出鞘的博客 5013

解决mongodb中BigDecimal和Decimal128互转异常

java 对象的使用BigDecimal 存入mongodb 时候,需要将BigDecimal 转成Decimal128 格式存储, 从mongodb中读取数据时候,需要将Decimal128转成BigDecimal 格式读取,否则就会报以下异常。 查询时异常 No converter found capable of converting from type [org.bson.types.Decimal128] to type [java.math.BigDecimal] 保存,修改时异常

洛阳泰山的博客 5140

springboot日期及BigDecimal处理

springboot jackson日期和BigDecimal处理概述jackson简单使用springboot使用自定义序列化属性序列化 概述 jackson简单使用 springboot是使用jackson来序列化和反序列化json数据,而jackson主要用到的是ObjectMapper类, 如以下简单实例 package com.test.jacson; import com.fasterxml.jackson.core.JsonProcessingException; import com.fa

weixin_47045374的博客 4374

一文告诉你:如何在trae中编译运行STM32程序,并让AI帮你修改代码

本文详细介绍了如何将STM32程序从Keil迁移到国产免费工具Trae,并利用AI进行代码修改的全过程。

水滴爬呀爬 4879

用Linkboy玩转Arduino:3小时搞定智能倒车雷达(附仿真文件下载)

本文详细介绍了如何利用Linkboy图形化编程工具,在3小时内快速搭建一个基于Arduino的智能倒车雷达项目。通过仿真环境,初学者无需硬件即可学习超声波测距原理、报警逻辑设计,并完成从虚拟仿真到实体硬件的完整流程。文章提供了清晰的步骤、调试技巧及功能扩展思路,并附有仿真文件,是入门Arduino和智能硬件制作的绝佳实践指南。

weixin_29159441的博客 402

Spring Boot自定义BigDecimal精度序列化

最近做项目时涉及大量对数字需要进行精度的控制,产品设计的各功能模块小数点后保留位数不一样,数据库设计的DECIMAL类型.对于接口设计前端同学肯定要求这个精度后端处理的,以往都是手工处理,现在看来太麻烦.能不能像@JsonFormat(pattern = "yyyy-MM-dd")格式化日期类型一样,去配置BigDecimal序列化呢?于是开始研究jackson序列化源码,很快找到了方案.。

weixin_38201175的博客 2162

MST-GAT: Enhancing Anomaly Detection in Multimodal Time Series with Intra- and Inter-Modal Attention

本文深入解析了MST-GAT模型,这是一种通过模态内与模态间注意力机制增强多模态时间序列异常检测的新方法。它通过构建图结构显式建模传感器间的复杂时空依赖,并结合时间卷积网络与联合优化策略,有效降低了传统方法中常见的误报与漏报问题,在工业监控等场景中展现出卓越性能。

weixin_29079671的博客 150

从零开始学springboot-详解金钱类BigDecimal

https://mp.weixin.qq.com/s/NoP6ItZVq9a4hDDZfbrKpA

qq_32814555的博客 1530

Linux系统centos7安装网卡驱动

有时候我们装完Centos或Ubuntu系统会发现没有网卡信息,说明网卡驱动不配置,所以我们要重新安装。 首先去服务器主板官网下载网卡驱动,注意32位和64位。 先查看网卡型号 lspci | grep -i ethernet 我的网卡型号是 00:1f.6 Ethernet controller: Intel Corporation Device 0d55。 网上一找,压根没找到这型号的网卡,别说驱动了。怀着试一试的心态,就安装i219-v系的网卡驱动,还别说,成功了。 针对i21...

wshc18的博客 2万+

IC版图设计布局经验90条!

13 如果一个cell调用其它cell,被调用的cell的vssx,vddx,vssb,vddb如果没有和外层cell连起来,要打上PIN,否则通不过diva检查.尽量在布局低层cell时就连起来。48 在匹配电路的mos管左右画上dummy,用poly,poly的尺寸与管子尺寸一样,dummy与相邻的第一个poly gate的间距等于poly gate之间的间距。8 更改cell时查看路径,一定要在正确的library下更改,以防copy过来的cell是在其他的library下,被改错。

weixin_44606964的博客 909

SpringBoot使用fastjson的JsonField注解序列化Bigdecimal

代码 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLoc...

weixin_34413357的博客 6178

财务数字化——解读美的战略规划之财务组织体系建设【附全文阅读】

本文提出适用于集团企业的财务管控方案,面向财务负责人、HR及战略规划人员。方案整合四种管控模式,结合500强案例,构建"职能定位-架构设计-权责划分-人才发展"体系,涵盖财务五大模块。通过明确总部与事业部权责边界,提供组织架构等实操框架,旨在平衡财务管控与业务支持,提升效率与风控能力,满足集团财务体系规范化建设需求。

cdfunlove的博客 663

SpringBoot 转 Json 对 BigDecimal 格式化

SpringBoot 转 Json 对 BigDecimal 格式化 ——SpringBoot 返回对象自动转 Json 时对 BigDecimal 格式化 先说全局配置; 最后说怎样局部配置 (去掉两个注解就行); ——感谢原文: https://www.jianshu.com/p/db07543ffe0a 经过一番操作, 可以达到下面的效果 public class Example{ // 不加 @BigDecimalFormat 注解, 在输出后转为 1.23 private

weixin_53008424的博客 6872

全球建筑物提取数据集(免费下载):微软/GlobalMLBuildingFootprints

这个是GitHub上的开源数据集: https://github.com/microsoft/GlobalMLBuildingFootprints 介绍 必应地图正在世界各地发布开放式建筑足迹。我们从 2014 年到 2021 年间的 Bing Maps 图像中检测到了 7.77 亿座建筑物,包括 Maxar 和 Airbus 的图像。数据可在 ODbL 下免费下载和使用。该数据集补充了我们的其他版本。 包括的地区 执照 此数据由 Microsoft 根据Open Dat..

此星光明博客 6288

专为AI打造的浏览器:内存占用仅为Chrome的1/9、比Chrome快11倍(Docker部署教程,支持飞牛nas等服务器部署)

🚀 专为AI打造的无头浏览器来了! 用Zig从零构建,内存仅Chrome的1/9,速度快11倍,原生CDP协议支持Docker部署,适合爬虫、自动化测试和AI代理应用。✨

XiaoqiangClub的博客 730

SpringBoot Resp返回BigDecimal浏览器精度丢失

MappingJackson2HttpMessageConverter的类里面即可。这个时候需要统一一下格式。spring默认使用Jackson做序列化和反序列化。ObjectMapper 去配置SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN发现不能成功实现想要的。数据库存100.00的时候 前端显示会变成100。数据库存100.01的时候 前端显示100.01。实现一个序列化机 然后注入 给他丢到继承了。

qq_40914968的博客 1165

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

springboot解决Long /BigInteger /BigDecimal类型数据传给前端损失精度问题

import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.spring.

persistence勿忘初心 3295

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

[AIGC] 自定义Spring Boot中BigDecimal的序列化方式

首先,我们需要创建一个自定义序列化器类,这个类需要继承这个类,并重写serialize方法。这个方法的作用就是告诉Jackson如何将Java对象转换为JSON。创建一个类,我们可以将其命名为if(value!= null) {// 将BigDecimal保留3位小数,注意需要四舍五入 BigDecimal decimal = value . setScale(3 , BigDecimal . ROUND_HALF_UP);= null) {

程序员三木的博客 2562

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

SpringBoot BigDecimal精度丢失

BigDecimal精度丢失问题解决

JAVA老司机,热爱代码,技术卓绝。 916

【MongoDB】springboot项目里BigDecimal和Decimal128类型的转换

源码:https://github.com/nieandsun/mongstudy 我觉得我现在应该是我们组里mongo用的最菜的,因此打算系统的学习一下mongo!!! 1.简介 java里会用BigDecimal类型来表示精度要求较高的数字,而mongo从3.4开始也有了一个表示高精度数字的类型即Decimal128;但是两者之间不能直接进行转换. 描述一下现象,大家可以自己亲手试一下: ...

nrsc 1万+

JSON格式转BigDecimal类型

项目场景: springboot项目基础下,jdk1.8 问题描述: 做的是与第三方对接接口,接收其他团队传来的json格式对象,并把它转换为BigDecimal类型接收,Post请求接收 原因分析: 起初我想不就是个简单的json格式转换嘛,都是为了头发嘛,想着随便查个帖子就搞定了,但没想到各种帖子方式都试过了,均以失败告终。然后以自己的方式先输出接收的参数,是json键值对格式的,我为啥不试试Map接收然后转成String类型,最后再转成BigDecimal呢,说干就干..

王小坏 4040

BigDecimal的使用与工具类

创建一个具有参数所指定整数值的对象创建一个具有参数所指定双精度值的对象创建一个具有参数所指定长整数值的对象创建一个具有参数所指定以字符串表示的数值的对象。

小薛博客-助力人人成为架构师 789

BigDecimal的使用

创建一个具有参数所指定整数值的对象创建一个具有参数所指定双精度值的对象创建一个具有参数所指定长整数值的对象创建一个具有参数所指定以字符串表示的数值的对象。

小薛博客-助力人人成为架构师 952

SpringBoot 返回 BigDecimal ,数值太小导致返回科学计数法

1、自定义 FastJsonHttpMessageConverter ,放置list首位或,移除其他 json messageConverter。1、自定义ObjectMapper替换 或 自定义 MappingJackson2HttpMessageConverter。SerializerFeature.WriteBigDecimalAsPlain //防止科学计数法。2、配置 objectMapper。针对使用 Jackson 返回。针对使用 Fastjson返回。

z69183787的专栏 1556
上一篇: 27.2.从零开始学springboot-运行原理
下一篇: 29.从零开始学springboot-批量“覆盖导入”&“更新导入”
码哥说
博客等级 码龄8年 5645粉丝 172原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码哥说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值