当前位置:主页 > java教程 > Java BigDecimal使用避坑

Java中BigDecimal使用注意避坑指南

发布:2023-03-28 16:15:01 59


给网友们整理相关的编程文章,网友殳歆然根据主题投稿了本篇教程内容,涉及到java、bigdecimal用法、bigdecimal类型数据处理、java中bigdecimal、Java BigDecimal使用避坑相关内容,已被910网友关注,如果对知识点想更进一步了解可以在下方电子资料中获取。

Java BigDecimal使用避坑

前言

在java.math包中提供了对大数字的操作类,用于进行高精确计算,如BigInteger,BigDecimal类。而平常我们开发中使用最多的float和double只能适用于一般的科学和工程计算,如果要在比较精确的计算方面如货币,那么使用float和double会相应的丢失精度,因此用于精密计算大数字的类BigDecimal就必不可少了。所以BigDecimal适合商业计算场景,用来对超过16位有效位的数进行精确的运算。但是BigDecimal的使用并不像float和double那样,使用不当造成的后果更严重,下面就来看下我们项目中踩过BigDecimal的坑:

一. BigDecimal的初始化精度丢失问题

先来看下面代码的运行结果:

BigDecimal bd1 = new BigDecimal(0.1);
System.out.println("bd1="+bd1);
BigDecimal bd2 = new BigDecimal("0.1");
System.out.println("bd2="+bd2);
BigDecimal bd3 = BigDecimal.valueOf(0.1);
System.out.println("bd3="+bd3);

输出结果:

bd1=0.1000000000000000055511151231257827021181583404541015625
bd2=0.1
bd3=0.1

如果是float或double类型转Bigdecimal,不要使用new BigDecimal()转, 使用valueOf()方法 或 new BigDecimal(“”)转成string,否则有可能出现精度问题。

《Effective Java》这本书里说过:
如果需要精确的答案,请避免使用float和double

因为float和double执行的是二进制浮点运算,二进制有些情况下不能准确的表示一个小数,就像十进制不能准确的表示1/3(1/3=0.3333…)也就是说二进制表示小数的时候只能够表示能够用1/(2^n)的和的任意组合,例如:

  • 0.5能够表示,因为它可以表示成为1/2
  • 0.75也能够表示,因为它可以表示成为1/2+1/(2^2)
  • 0.875也能够表示,因为它可以表示成为1/2+1/(22)+1/(23)
  • 但是0.1不能够精确表示,因为它不能够表示成为1/(2^n)的和的形式
System.out.println(0.5*3);
System.out.println(0.1*3);

大家可以本地执行下这两行代码,看下输出结果就知道为什么二进制不能表示0.1却可以表示0.5了。所以其实不是BigDecimal的问题,BigDecimal就是为了满足精确运算存在的,问题出在0.1它本身就一个不准确的值,这其实跟BigDecimal无关,但在使用的时候需要注意用法。

二. BigDecimal在进行除法运算时需设置精度,否则对于除不尽的情况会抛出异常

继续看下面的代码执行结果:

BigDecimal bd4 = new BigDecimal("10");
BigDecimal bd5 = new BigDecimal("3");
System.out.println(bd4.divide(bd5));

输出结果:

Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1690)
at BigDecimalTest.main(BigDecimalTest.java:38)

应该向下面这样设置小数点后的位数,以及超出后是四舍五入和向上/向下取整或者直接舍弃:

System.out.println(bd4.divide(bd5,2,BigDecimal.ROUND_DOWN));

第二个参数表示小数位数,第三个参数表示超出的位数直接舍弃(当然也可以设置四舍五入,向上取整等)

三. 不要使用BigDecimal的equals方法比较大小, 否则可能会因为精度问题导致比较结果和预期的不一致

BigDecimal bd1 = new BigDecimal("0");
BigDecimal bd2 = new BigDecimal("0.0");
System.out.println(bd1.equals(bd2));
System.out.println(bd1.compareTo(bd2) == 0)

输出结果:

equals:false
compareTo:true

如果你无法确定你的BigDecimal值有小数情况,最好用compareTo!

补充:BigDecimal比较值大小避坑

注意点

但是,对于BigDecimal的大小比较,用equals方法的话会不仅会比较值的大小,还会比较两个对象的精确度,而compareTo方法则不会比较精确度,只比较数值的大小。这也是很多人比较容易踩的坑。下面给大家做一下示例:

 BigDecimal bigDecimal1 = new BigDecimal("1.350000000000");
 BigDecimal bigDecimal2 = new BigDecimal("1.35");
 System.out.println("bigdecial1:"+bigDecimal1);
 System.out.println("bigdecail2:"+bigDecimal2);
 System.out.println(bigDecimal1.equals(bigDecimal2)); //false
 System.out.println(bigDecimal1.compareTo(bigDecimal2)); // 0 代表相等

运行结果:

bigdecial1:1.350000000000
bigdecail2:1.35
false
0

总结

到此这篇关于Java中BigDecimal使用注意避坑指南的文章就介绍到这了,更多相关Java BigDecimal使用避坑内容请搜索码农之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持码农之家!


参考资料

相关文章

  • 实例解析Java Chaos Game噪声游戏

    发布:2020-03-06

    这篇文章主要介绍了Java Chaos Game噪声游戏实例代码,具有一定借鉴价值,需要的朋友可以参考下。


  • java 9大性能优化经验总结

    发布:2023-03-30

    这篇文章主要介绍了java 9大性能优化经验总结,包括:Java代码优化,数据库优化,分布式缓存,异步化,Web前段,搜索引擎优化等需要的朋友可以参考下


  • 怎样使用JavaScript中的setUTCDate()方法

    发布:2020-02-11

    这篇文章主要介绍了JavaScript中的setUTCDate()方法使用详解,是JS入门学习中的基础知识,需要的朋友可以参考下


  • 详解Java中运算符及用法

    发布:2022-06-22

    为网友们分享了关于Java运算符的教程,这篇文章主要介绍了详解Java中运算符以及相关的用法讲解,一起跟着小编学习下吧。


  • Java之Mybatis多层嵌套查询方式

    Java之Mybatis多层嵌套查询方式

    发布:2023-01-16

    给大家整理了关于Java的教程,这篇文章主要介绍了Java之Mybatis多层嵌套查询方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教


  • java常量字符串过长报错的解决办法以及原因分析

    发布:2023-04-20

    在IDEA中字符串长度超过65535,进行打印,IDEA会提示java:常量字符串过长,这篇文章主要给大家介绍了关于java常量字符串过长报错的解决办法以及原因分析,需要的朋友可以参考下


  • JavaWeb项目FullCalendar日历插件实例用法

    发布:2020-06-13

    本篇文章主要介绍了JavaWeb项目FullCalendar日历插件使用的示例代码,具有一定的参考价值,有兴趣的可以了解一下


  • Java String字符串和Unicode字符相互转换实例代码

    发布:2019-12-24

    这篇文章主要介绍了Java String字符串和Unicode字符相互转换代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习


网友讨论