2026/1/14 1:32:46
网站建设
项目流程
新沂做网站,温州公司建设网站制作,网站建设业务员主要工作,网易企业邮箱可以全部转发么在Java开发中#xff0c;你是不是也遇到过这样的“玄学问题”#xff1a;明明是简单的小数计算#xff0c;结果却跑偏了#xff1f;比如0.1 0.2#xff0c;得到的不是0.3#xff0c;而是0.30000000000000004#xff1f;
其实这不是Java的bug#xff0c;而是浮点型数据…在Java开发中你是不是也遇到过这样的“玄学问题”明明是简单的小数计算结果却跑偏了比如0.1 0.2得到的不是0.3而是0.30000000000000004其实这不是Java的bug而是浮点型数据float、double的“天生缺陷”。由于计算机无法精确表示部分十进制小数在金融、电商等对精度要求极高的场景中用float、double计算简直是“灾难”。而今天的主角——BigDecimal就是为解决精度问题而生的“神器”。这篇文章就带大家彻底搞懂BigDecimal它是什么、怎么用以及那些容易踩的坑一、为什么必须用BigDecimal先再看一个直观的例子感受下float、double的精度问题publicclassTest{publicstaticvoidmain(String[]args){System.out.println(0.10.2);// 输出0.30000000000000004System.out.println(1.0-0.8);// 输出0.19999999999999996System.out.println(2.01*2);// 输出4.019999999999999System.out.println(2.02/2);// 输出1.0100000000000002}}如果用这样的结果处理订单金额、财务核算后果不堪设想。而BigDecimal是Java.math包下的类专门用于高精度的十进制数运算。它能精确表示任意精度的小数从根源上解决了浮点型的精度丢失问题是金融、电商等领域的“标配”。二、BigDecimal核心用法从入门到实战掌握以下几个核心用法就能应对大部分开发场景1. 正确创建BigDecimal对象创建BigDecimal的方式有多种但很多人第一坑就踩在这里先看错误示例// 错误用法用double创建依然会有精度问题BigDecimalwrong1newBigDecimal(0.1);System.out.println(wrong1);// 输出0.1000000000000000055511151231257827021181583404541015625原因0.1这个十进制小数无法用二进制精确表示用double创建BigDecimal时会把double的精度误差带进来。✅ 正确创建方式// 方式1用String构造推荐无精度丢失BigDecimalcorrect1newBigDecimal(0.1);System.out.println(correct1);// 输出0.1// 方式2用BigDecimal.valueOf()推荐内部会处理精度BigDecimalcorrect2BigDecimal.valueOf(0.1);System.out.println(correct2);// 输出0.1// 方式3创建整数无精度问题可直接用构造器BigDecimalcorrect3newBigDecimal(10);System.out.println(correct3);// 输出10重点记住创建小数类型的BigDecimal优先用String构造或BigDecimal.valueOf()创建整数类型可直接用构造器。2. 核心运算加减乘除BigDecimal没有重载、-、*、/等运算符必须通过自身的方法进行运算。方法名很直观add加、subtract减、multiply乘、divide除。publicclassBigDecimalCalc{publicstaticvoidmain(String[]args){BigDecimalanewBigDecimal(0.1);BigDecimalbnewBigDecimal(0.2);// 1. 加法BigDecimaladdResulta.add(b);System.out.println(0.1 0.2 addResult);// 输出0.3// 2. 减法BigDecimalsubResultnewBigDecimal(1.0).subtract(newBigDecimal(0.8));System.out.println(1.0 - 0.8 subResult);// 输出0.2// 3. 乘法BigDecimalmulResultnewBigDecimal(2.01).multiply(newBigDecimal(2));System.out.println(2.01 * 2 mulResult);// 输出4.02// 4. 除法重点除法可能出异常BigDecimaldivResultnewBigDecimal(2.02).divide(newBigDecimal(2));System.out.println(2.02 / 2 divResult);// 输出1.01}}⚠️ 除法注意事项如果除数和被除数无法整除会抛出ArithmeticException异常比如1÷3// 错误用法1÷3无法整除抛出异常BigDecimalwrongDivnewBigDecimal(1).divide(newBigDecimal(3));// 报错java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.✅ 正确处理指定精度和舍入模式这是除法的核心必须掌握// 格式divide(除数, 保留小数位数, 舍入模式)BigDecimalcorrectDivnewBigDecimal(1).divide(newBigDecimal(3),2,RoundingMode.HALF_UP);System.out.println(1 ÷ 3 correctDiv);// 输出0.333. 关键舍入模式RoundingMode舍入模式决定了小数部分如何处理常用的有以下几种对应实际开发中的不同场景RoundingMode.HALF_UP四舍五入最常用比如保留2位小数0.335→0.34RoundingMode.HALF_DOWN五舍六入0.335→0.330.336→0.34RoundingMode.UP向上取整不管小数是多少都进1比如0.331→0.341.001→2.00RoundingMode.DOWN向下取整直接舍弃小数部分比如0.339→0.33RoundingMode.CEILING向正无穷取整正数向上负数向下比如1.001→2.00-1.001→-1.00RoundingMode.FLOOR向负无穷取整正数向下负数向上比如1.009→1.00-1.009→-2.00实际开发中金融场景优先用HALF_UP四舍五入具体需遵循业务规则比如有些银行可能要求“四舍六入五留双”对应RoundingMode.HALF_EVEN。4. 比较大小别用equals很多人会用equals()方法比较两个BigDecimal是否相等但这也是一个坑因为equals()不仅比较数值还会比较精度。// 错误示例数值相等但精度不同equals返回falseBigDecimalnum1newBigDecimal(1.0);BigDecimalnum2newBigDecimal(1.00);System.out.println(num1.equals(num2));// 输出false✅ 正确比较方式用compareTo()方法返回值是int类型返回0两个数值相等返回1当前对象大于参数对象返回-1当前对象小于参数对象BigDecimalnum1newBigDecimal(1.0);BigDecimalnum2newBigDecimal(1.00);BigDecimalnum3newBigDecimal(1.1);System.out.println(num1.compareTo(num2));// 输出0相等System.out.println(num1.compareTo(num3));// 输出-1num1 num3System.out.println(num3.compareTo(num1));// 输出1num3 num1三、开发中必避的5个坑坑1用double构造BigDecimal→ 解决方案用String或valueOf()坑2除法不指定精度→ 解决方案divide()方法必须传舍入模式坑3用equals()比较大小→ 解决方案用compareTo()方法坑4忽视BigDecimal的不可变性→ 注意BigDecimal的运算方法不会修改自身而是返回新的对象坑5不必要的精度保留→ 比如订单金额保留2位小数即可过多的精度会增加存储和计算成本可通过setScale()方法设置精度四、总结BigDecimal的核心价值就是高精度运算只要记住以下几点就能轻松上手创建小数用String构造或valueOf()避免double运算用add/subtract/multiply/divide方法除法必须指定精度和舍入模式比较大小用compareTo()不用equals()记住它是不可变对象运算后要接收新对象。在金融、电商等对精度敏感的场景一定要用BigDecimal替代float、double如果还有其他关于BigDecimal的疑问欢迎在评论区留言