用了BigDecimal就不會資損?了解下BigDecimal這五個坑
往期熱門文章:
1、一個依賴搞定 Spring Boot 反爬蟲,防止接口盜刷!
BigDecimal而導致故障的文章,但是除非在一些非常簡單的場景,結(jié)算匯金類的業(yè)務也不會直接用BigDecimal來計算金額,原因有兩點:BigDecimal里面還是有很多隱蔽的坑的BigDecimal沒有提供金額的單位
1. BigDecimal中的五個容易踩的坑
1.1 new BigDecimal()還是BigDecimal#valueOf()?
BigDecimal bd1 = new BigDecimal(0.01);
BigDecimal bd2 = BigDecimal.valueOf(0.01);
System.out.println("bd1 = " + bd1);
System.out.println("bd2 = " + bd2);
bd1 = 0.01000000000000000020816681711721685132943093776702880859375
bd2 = 0.01
BigDecimal的時候就已經(jīng)丟精度了,而BigDecimal#valueOf的實現(xiàn)卻完全不同public static BigDecimal valueOf(double val) {
// Reminder: a zero double returns '0.0', so we cannot fastpath
// to use the constant ZERO. This might be important enough to
// justify a factory approach, a cache, or a few private
// constants, later.
return new BigDecimal(Double.toString(val));
}
BigDecimal對象,因此避免了精度問題。所以大家要盡量要使用字符串而不是浮點數(shù)去構(gòu)造BigDecimal對象,如果實在不行,就使用BigDecimal#valueOf()方法吧。1.2 等值比較
BigDecimal bd1 = new BigDecimal("1.0");
BigDecimal bd2 = new BigDecimal("1.00");
System.out.println(bd1.equals(bd2));
System.out.println(bd1.compareTo(bd2));
false
0
BigDecimal中equals方法的實現(xiàn)會比較兩個數(shù)字的精度,而compareTo方法則只會比較數(shù)值的大小。1.3 BigDecimal并不代表無限精度
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("3.0");
a.divide(b) // results in the following exception.
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
JVM我們不需要返回精確的結(jié)果就好了BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("3.0");
a.divide(b, 2, RoundingMode.HALF_UP)// 0.33
1.4 BigDecimal轉(zhuǎn)回String要小心
BigDecimal d = BigDecimal.valueOf(12334535345456700.12345634534534578901);
String out = d.toString(); // Or perform any formatting that needs to be done
System.out.println(out); // 1.23345353454567E+16
BigDecimal有三個方法可以轉(zhuǎn)為相應的字符串類型,切記不要用錯:String toString(); // 有必要時使用科學計數(shù)法
String toPlainString(); // 不使用科學計數(shù)法
String toEngineeringString(); // 工程計算中經(jīng)常使用的記錄數(shù)字的方法,與科學計數(shù)法類似,但要求10的冪必須是3的倍數(shù)
1.5 執(zhí)行順序不能調(diào)換(乘法交換律失效)
BigDecimal a = BigDecimal.valueOf(1.0);
BigDecimal b = BigDecimal.valueOf(3.0);
BigDecimal c = BigDecimal.valueOf(3.0);
System.out.println(a.divide(b, 2, RoundingMode.HALF_UP).multiply(c)); // 0.990
System.out.println(a.multiply(c).divide(b, 2, RoundingMode.HALF_UP)); // 1.00
2. 最佳實踐
BigDecimal再封裝一個Money類,其實我們直接可以用一個半官方的Money類:JSR 354 ,雖然沒能在Java 9中成為Java標準,很有可能集成到后續(xù)的Java版本中成為官方庫。2.1 maven坐標
<dependency>
<groupId>org.javamoney</groupId>
<artifactId>moneta</artifactId>
<version>1.1</version>
</dependency>
2.2 新建Money類
CurrencyUnit cny = Monetary.getCurrency("CNY");
Money money = Money.of(1.0, cny);
// 或者 Money money = Money.of(1.0, "CNY");
//System.out.println(money);
2.3 金額運算
CurrencyUnit cny = Monetary.getCurrency("CNY");
Money oneYuan = Money.of(1.0, cny);
Money threeYuan = oneYuan.add(Money.of(2.0, "CNY")); //CNY 3
Money tenYuan = oneYuan.multiply(10); // CNY 10
Money fiveFen = oneYuan.divide(2); //CNY 0.5
2.4 比較相等
Money fiveFen = Money.of(0.5, "CNY"); //CNY 0.5
Money anotherFiveFen = Money.of(0.50, "CNY"); // CNY 0.50
System.out.println(fiveFen.equals(anotherFiveFen)); // true
BigDecimal的一些坑。往期熱門文章:
1、線上MySQL的自增id用盡怎么辦?被面試官干趴下了! 2、計算機專業(yè)會不會成為下一個土木? 3、xxl-job驚艷的設計,怎能叫人不愛 4、ArrayList#subList這四個坑,一不小心就中招 5、面試官:大量請求 Redis 不存在的數(shù)據(jù),從而影響數(shù)據(jù)庫,該如何解決? 6、MySQL 暴跌! 7、超越 Xshell!號稱下一代 Terminal 終端神器,用完愛不釋手! 8、IDEA 官宣全新默認 UI,太震撼了??! 9、讓你直呼「臥槽」的 GitHub 項目! 10、Kafka又笨又重,為啥不選Redis?
評論
圖片
表情
